了解类和对象前,简单提及面向对象程序设计。面向对象程序设计就是通过对象来进行程序设计,对象表示一个可以明确标识的实体。例如:一个人、一本书、一个学校或一台电脑等等。每个对象都有自己独特的标识、状态和行为。

对象的状态(特征或属性,即实例变量),由该对象的数据域来表示。 例如:一个人可以具有名字、年龄、身高、体重、家庭地址等等属性,这些就是“人这个对象的数据域”。

对象的行为(对象执行的动作,即功能),由方法来定义。例如:定义getName()来获取姓名, getHeight()获取身高,setAddress(String addr)修改地址。

类和对象的关系

类是一种抽象的概念集合,是最基础的组织单位,作为对象的模板、合约或蓝图。

类是对象的类型,使用一个通用类可以定义同一类型的对象,类中定义对象的数据域是什么以及方法是做什么的。 对象是类的实例,一个类可以拥有多个实例,创建实例的过程叫做实例化。实例也称为对象,两者说法一致。

用几个案例来加深理解类和对象。

  

上面的几个类定义了该类对象的数据域和方法, 但这些类中都没有main()方法,所以无法运行。注意:拥有main()方法的类称为主类,是执行程序的入口。使用类中定义的数据域和方法需要创建该类的实例,然后用实例来调用。

public class TestCreateInstance {
public static void main(String[] args) {
//创建Fruit类的实例
Fruit f = new Fruit("香蕉", "甜味");
System.out.println(f.toString()); //显示f实例中的水果信息 //创建Book类的实例
Book b = new Book("Java案例学习", "IT", 25.5, "A0001");
System.out.println(b.toString()); //显示b实例中的书籍信息 //创建Person类的实例
Person p = new Person("张三", 1, 18, "中国北京");
System.out.println(p.toString()); //result
// 水果名:香蕉, 口味:甜味
// 书名:Java案例学习, 书的种类:IT, 单价:25.5, 书籍编号:A0001
// 名字:张三, 性别:1,年龄:18, 出生地:中国北京
}
}

这里定义了带有main()方法的TestCreateInstance类,用于测试其他三个类。在main方法中,一共创建了三个对象, 创建对象使用new操作符, new Class(parameter)表示调用该类中相应参数的构造方法。

例如 new Fruit("香蕉", "甜味") 会调用 Fruit(String name, String state) 这个构造方法来创建对象。

构造方法

构造方法在使用new操作符创建对象时被调用,作用就是用于初始化对象数据域。

构造方法相比于普通方法比较特殊的地方: 构造方法名和所在类的类名一致;无返回值(即void也没有);只有创建对象时才会被调用。  构造方法和普通方法一样,也可以重载,根据不同的初始参数,来构造对象。

    //只初始化名字和性别
public Person(String name, int sex) {
this.name = name;
this.sex = sex;
}
  
public Person(String name, int sex, int age, String birthplace) {
this(name, sex); //使用this()来调用类中的构造器
this.age = age;
this.birthplace = birthplace;
}

除了定义有参构造方法,也可以定义无参构造方法: public Person(){}。若一个类中没有定义任何构造方法,那么在类中会隐式存在一个方法体为空的无参构造方法,也叫默认构造方法。如果显式的定义构造方法,则默认构造方法失效。

为什么要有默认构造方法呢?这就要提到构造方法中的调用流程了,即“构造方法链”。  这里涉及到继承的相关知识,这里不给出。

引用变量访问对象和调用数据域和方法

对象是通过对象类型变量来访问,该变量包含了对对象的引用。对象类型变量使用操作符(.)来 访问对象数据和方法。 

创建的对象会在内存中分配空间, 然后通过引用变量来访问。 包含一个引用地址的变量就是引用变量, 即引用类型。 Java中,除了基本类型外,就是引用类型(对象)。

声明对象类型变量的两种形式

Fruit f ; //只声明,未指向一个引用地址
Fruit f = null; //f指向一个空地址
//两者基本无区别,null是引用类型的默认值

本质上来看,类是一种自定义类型,是一种引用类型,所以该类类型的变量可以引用该类的一个实例。 

Fruit f = new Fruit("西瓜", "“甜味”)

//表示创建一个Fruit对象,并返回该对象的引用,赋给Fruit类型的f变量。  变量f包含了一个Fruit对象的引用地址。 但通常情况下,直接称变量f为Fruit对象。

引用类型变量和基本类型变量的区别

每一个变量都代表一个存储值的内存位置。 声明变量时,就是告知编译器该变量可以存储什么类型的值。对基本类型变量来说,对应内存所存储的值就是基本类型值。而对于引用类型变量来说,对应内存所存储的值是一个引用,指向对象在内存中的位置。

除了基本类型,就是引用类型,引用类型包含对象引用,可以将引用类型看作对象。

        int a = 6;
int b = a; //将a的实际值赋给b
TestReferance tr = new TestReferance();
TestReferance t2 = tr; //将tr的引用赋给t2 , tr和t2指向同一对象
t2.a = 10;
System.out.println(tr.a); //

所以,将引用类型变量赋值给另一个同类型引用变量,两者会指向同一个对象,而不是独立的对象。 如果想要指向一个具有同样内容,但不是同一个对象,可以使用clone()方法。

【技巧】:如果不再需要某个对象时,也就是不引用该对象,可以将引用类型变量赋值null,表示引用为空。 若创建的对象没有被任何变量所引用,JVM会自动回收它所占的空间。

        TestReferance t1 = new TestReferance();
t1 = new TestReferance(); //t1指向一个新的对象。 t1原来指向的对象会被回收
//创建一个匿名对象,执行完构造方法后,就会被回收。
new TestReferance();

PS:关于NullPointerException异常,一般都是因为操作的引用类型变量指向null,所以对引用类型变量操作时,最好先判断一下是否为null。

静态与实例的区别

上面的类中定义的都是实例变量和实例方法,这些数据域和方法属于类的某个特定实例,只有创建该类的实例后,才可以访问对象的数据域和方法。

静态变量和方法属于类本身,静态变量被类中的所有对象共享,在静态方法中不能直接访问实例变量和调用实例方法。

public class Test {
public int a = 5;
public static int staB = 10;
public Test(int a) { this.a = a; }
public static void main(String[] args) {
Test t1 = new Test(6);
Test t2 = new Test(8);
System.out.println(t1.a + " " + t2.a); // 6 8, 两个对象互不相关
t1.staB = 15; //t1对象修改静态变量 staB
System.out.println(t2.staB); //影响t2对象
}
}
public class Test {
public int a = 5; //实例变量
public static int staB = 10; //静态变量
public Test(int a) { this.a = a; } public static void staMethod() {
System.out.println(a); //error, 不允许直接访问实例变量
insMethod(); //不允许直接调用实例方法 //通过对象来调用
System.out.println(new Test(5).a);
new Test(5).insMethod(); }
//实例方法中,可直接访问静态变量和调用静态方法
public void insMethod() {
staMethod();
System.out.println(staB);
}
}

因为静态变量将变量值存储在一个公共地址,被该类的所有对象共享,当某个对象对其修改时,会影响到其他对象。而实例的实例变量则是存储在不同的内存位置中,不会相互影响。

访问静态变量和静态方法时,可以不用创建对象,通过“类名.静态变量/静态方法”来访问调用。 虽然能通过对象来访问静态变量和方法,但为了可读性,方便分辨静态变量,应该通过类名来调用。

【技巧】:若想要某个数据被所有对象共享,就可以使用static修饰,例如常量,修饰常量使用public static final。

【技巧】:如果某个变量或方法依赖于类的某个实例,则应该定义成实例变量或实例方法。若某个变量或方法不依赖于类的某个实例,则应该定义成静态变量和静态方法。 例如Math类,只有静态方法和静态变量,禁止创建Math对象。

不可变对象和类

通过定不可变类来产生不可变对象,不可变对象的内容不能被改变。就像文件中的“只读”概念。

通常情况下,创建一个对象后,该对象的内容可以允许之后修改。但有时候我们需要一个一旦创建,其内容就不能改变的对象。

定义不可变类的要素:

类中所有数据域都是私有的,并且没有提供任何一个数据域的setXxx()方法。若数据域是可变的引用类型,不提供返回该引用类型变量的getXxx()方法。

public class Test {
private int a = 5;
private String str; //String是不可变对象,它的方法都是返回一个新的String对象
private Date date;
public Test(int a, String str, Date date) {
super();
this.a = a;
this.str = str;
this.date = date;
}
public static void main(String[] args) {
Test t = new Test(5, "ABC", new Date());
System.out.println(t.toString());
//获取引用类型的数据域,其中Date是可变的
String s = t.getStr();
Date d = t.getDate();
s.toLowerCase();
//可变数据域
d.setDate(541313);
System.out.println(t.toString());
}
public int getA() {
return a;
} public String getStr() {
return str;
}

从以上案例看出,如果数据域是一个可变的引用类型,那么不要返回该数据域,不然对返回的引用变量进行操作,会导致对象内容改变。

this关键字的使用

关键字this表示当前对象,引用对象自身。 可以用于访问实例的数据域, 尤其是实例变量和局部变量同名时,进行分辨。除此之外,可以在构造方法内部调用同一个类的其他构造方法。

以构造方法为例

    public int a;
public String str;
//不使用this来初始化构造方法
public TestThis(int a, String str) {
//隐式存在于每个构造方法的第一行
super();
a = a; //指向同名局部变量形参a
str = str; //指向同名局部变量形参str
}

形参名和全局变量同名,但形参是局部变量,所以在方法中优先使用局部变量,这里的赋值是赋值给形参了。解决这个问题,可以修改形参名,但形参名和要初始化的变量名不相等容易引起歧义。

所以使用this来引用实例变量,一举两得。

    public int a;
public int b;
public int c;
//构造方法1
public TestThis(int a, int b) {
this.a = a;
this.b = b;
} //构造方法2
public TestThis(int a, int b, int c) {
this(a, b); //调用构造方法1来简化初始化操作
this.c = c;
}

引用参数传递给方法

方法是一种功能集合,表明可以做什么,封装了实现功能的代码,要实现某个功能只需要调用相关方法即可,无需关注功能实现细节。大部分方法都需要传递参数来实现相关功能,但是传递基本类型和传递引用类型有什么区别呢?

给方法传递一个对象参数,实际上是将对象的引用传递给方法。

public class TestThis {
public static void main(String[] args) {
int[] arr = {1, 2};
swap(arr[0], arr[1]);
System.out.println(Arrays.toString(arr)); //[1, 2]
swap(arr);
System.out.println(Arrays.toString(arr)); //[2, 1] }
public static void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
public static void swap(int[] a) {
int temp = a[0];
a[0] = a[1];
a[1] = temp;
}
}

第一个swap()方法,接收基本类型参数,所以通过访问下标获取数组元素传递给形参,相当于赋一个实际值给形参,所以对形参交换,不会影响实际参数。

第二个swap()接收一个int类型数组, 数组也是一个对象, 所以此时形参a包含一个该数组的引用,在方法内部对a数组操作,会影响实际参数 arr。

上面方法中使用到了方法重载,方法重载就是使用同样的名字,但根据方法签名来定义多个方法。

方法重载只与方法签名有关,和修饰符以及返回类型无关。被重载的方法必须有不同的参数列表或者参数类型不同。

参数列表不同必然重载,若参数列表相同,但类型相近时,会引发匹配歧义,因为类型不明确。

     //因为double类型可以匹配int类型,所以会导致编译器匹配歧义
public static void sum(int a, double b) { }
public static void sum(double a, int b) { }

Java类和对象详解,以及相关知识点的更多相关文章

  1. java类和对象详解

    类和对象 java 是面向对象的语言 即 万物皆对象c语言是面向过程语言 一.怎么去描述一个对象? (1)..静态的(短时间内不会改变的东西) 例如:外观,颜色,品牌 (2).动态的(动作) 可以干什 ...

  2. Java类和对象 详解(一)---写的很好通俗易懂---https://blog.csdn.net/wei_zhi/article/details/52745268

    https://blog.csdn.net/wei_zhi/article/details/52745268

  3. java中Class对象详解和类名.class, class.forName(), getClass()区别

    一直在想.class和.getClass()的区别,思索良久,有点思绪,然后有网上搜了搜,找到了如下的一篇文章,与大家分享. 原来为就是涉及到Java的反射----- Java反射学习 所谓反射,可以 ...

  4. java中Class对象详解

    java中把生成Class对象和实例对象弄混了,更何况生成Class对象和生成instance都有多种方式.所以只有弄清其中的原理,才可以深入理解.首先要生成Class对象,然后再生成Instance ...

  5. 【转】 java中Class对象详解和类名.class, class.forName(), getClass()区别

    Class对象的生成方式如下: 1.类名.class           说明: JVM将使用类装载器, 将类装入内存(前提是:类还没有装入内存),不做类的初始化工作.返回Class的对象 2.Cla ...

  6. Java 类的继承详解

    /*文章中用到的代码只是一部分,需要完整代码的可通过邮箱联系我1978702969@qq.com*/ 在面向对象的语言中如C++和JAVA,都有一个比较重要的机制——类的继承.这里将对JAVA中的类的 ...

  7. java反射机制深入详解

    java反射机制深入详解  转自:http://www.cnblogs.com/hxsyl/archive/2013/03/23/2977593.html 一.概念 反射就是把Java的各种成分映射成 ...

  8. JavaWeb学习----JSP内置对象详解

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  9. Java Web(一) Servlet详解!!

    这篇文章到上一篇,距离的有点遥远呀,隔了大概有两个月把,中间在家过了个年,哈哈~ 现在重新开始拾起,最近在看一本个人觉得很棒的书,<Java Web 整合开发王者归来>,现在写的这一系列基 ...

随机推荐

  1. antd-mobile的按需加载

    "babel": { "presets": [ "react-app" ] } 主要问题是 依赖项的版本问题 以及 配置问题 新添加的con ...

  2. web前端面试题(持续更新)

    此文是我本人在面试的时候遇到的问题和一些同学遇到的问题加资料上面的问题的总结.(将会持续更新,因为未有满意工作) 面试时有几点需要注意: 1.面试题目:根据你的等级和职位的变化,入门级到大神级,广度和 ...

  3. 学习servlet心得

    1,关于字符编码问题: // resp.setCharacterEncoding("UTF-8");//这个的作用仅仅只是输出字符,不做格式转换成HTML // resp.setC ...

  4. GPG error: http://extras.ubuntu.com trusty Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY F60F4B3D7FA2AF80

    今天在更新运行apt-get update的时候出现了如下的错误: W: GPG error: http://extras.ubuntu.com trusty Release: The followi ...

  5. How to safely downgrade or remove glibc with yum and rpm

    Environment Red Hat Enterprise Linux 5 Red Hat Enterprise Linux 6 glibc, glibc-common, glibc-devel, ...

  6. 7.Java关键字和保留字

    一.概念 Java关键字(Key Word):  对Java的编译器有特殊的意义,他们用来表示一种数据类型或者表示程序的结构. 保留字(Reserve Word):即它们在Java现有版本中没有特殊含 ...

  7. java线程操作

    目录 前言 创建多线程的方式 1继承thread抽象类 2实现Runnable接口 3实现Callable接口 匿名内部类 线程池 线程安全 同步代码块 同步方法 锁机制 线程状态 前言 进程:内存运 ...

  8. Unity IOC/DI使用

    一.IOC介绍 IOC(Inversion of Control),中文译为控制反转,又称为“依赖注入”(DI =Dependence Injection) IOC的基本概念是:不创建对象,但是描述创 ...

  9. Nginx学习---企业级nginx环境搭建

    1.1. nginx安装环境 1.系统要求 nginx是C语言开发,建议在linux上运行,本教程使用Centos6.5作为安装环境. 1-1 安装 GCC 源码安装nginx需要依赖gcc环境,需要 ...

  10. Linux命令--目录处理

    ls命令 Linux ls命令用于显示指定工作目录下之内容(列出目前工作目录所含之文件及子目录). 语法 ls [-alrtAFR] [name...] 参数 : -a 显示所有文件及目录 (ls内定 ...