带你用Java全面剖析类和对象
作者:富春山居_ZYY
一、面向过程?面向对象?
C 语言是一门过程语言,在求解问题的时候关注的是过程,因此 C 语言是面向过程的。
JAVA 语言与之不同,JAVA 语言是面向对象的语言,在求解问题的时候,将问题拆分成好几个对象,对象与对象之间相互交互从而解决问题。对象是 JAVA 语言的核心。
用通俗的例子来解释这两者的区别就应该是这样的。
想要吃一碗蛋炒饭,如果是面向过程的话就应该是这样的。
如果是面向对象的话就应该是这样的。
过程:
我付钱厨子做蛋炒饭服务员将蛋炒饭端上来我吃蛋炒饭
整个过程是四个对象之间交互完成的,对于我而言,厨子具体炒蛋炒饭的步骤我并不需要知道,这就是面向对象。
在用 JAVA 进行设计开发时,我们需要做的就是找到对象,建立对象,使用对象,维护对象之间的关系。
二、类和类的实例化
类实际上就是一类对象的统称,相当于一个模板;对象其实就是对类实例化出来的结果,相当于由模板产生的样本。
一个模板可以产生多个样本,一个类可以实例化出多个对象。
在 JAVA 当中,类是一个引用类型,需要用到关键字 class 来申明一个类,实际上就相当于创建一个新的数据类型
基本语法形式:
//创建一个类 class <类的名字> { field;//成员变量 method;//成员方法 } //实例化一个对象 <类的名字> <对象名> = new <类的名字>();
2.1普通成员变量和普通成员方法
代码示例:
class Person { public int age; public String name;//成员变量放在对象当中,即堆上 public void show() { //int a = 10; //a变量定义在方法中,它不是成员变量,是局部变量,在栈上开辟内存 System.out.println("姓名: " + name + " 年龄: " + age); } } public class TestDemo { public static void main(String[] args) { Person person1 = new Person(); person1.age = 18; person1.name = "富春"; person1.show(); Person person2 = new Person(); person2.age = 21; person2.name = "山居"; person2.show(); } }
代码结果:
代码解释:
- 这里通过 class 这个关键字创建了 Person 这个类(类名通常用大驼峰即每个单词的首字母都为大写)。
- 像 age 和 name 这种定义在方法外部类内部的变量称之为 成员变量 或属性 或 字段 。另外,这两个变量皆为普通成员变量。
- 像 show 这种描述对象行为的叫做方法或行为,这里通过 show 方法将姓名和年龄进行了打印。另外,该方法为普通成员方法。
- 在 JAVA中通过类的实例(对象)点号(.)来访问类的成员变量和成员方法,格式为:对象名.成员变量; 对象名.成员方法(实参列表);(PS:在访问类的成员方法时,如果类的方法有形参,就必须为方法传递与参数类型相同的实参值)
- 在 main 函数中,实例化了两个对象,为对象在堆上开辟了内存,内存的地址存放在 person1 和 person2 中,因此这两个变量实际上是引用变量。其中的 new 关键字就是用于创建一个对象的实例。
内存分布:
注意:
- 当对象中的成员变量并没有赋初值时,引用类型默认为 null ,基本类型默认为 0 值,boolean 类型默认为 false ,char 类型默认为 '\u0000'(其实就是啥也没有)。
- 当引用类型的变量为 null 时,即表示不引用任何对象,此时对 null 进行访问,就会出现空指针异常。
- 如果不希望成员变量使用默认值时,可以在创建类的时候为成员变量赋初始值,但其意义不太大,类终究是个模板,创造的样本各种各样。
代码示例:
class Person { public int age; public String name; public boolean ans; public char ch; public void show() { System.out.println("姓名: " + name + " 年龄: " + age); System.out.println("ans:" + ans + " ch:" + ch); } } public class TestDemo { public static void main(String[] args) { Person person = new Person(); person.show(); } }
🏸 代码结果:
2.2 静态成员变量和静态成员方法
代码示例:
class Person { public int age; public static int count; public static final int COUNT = 99; //COUNT 是静态常量 public static void staticTest() { System.out.println("这是静态成员方法"); } } public class TestDemo { public static void main(String[] args) { Person person1 = new Person(); person1.age = 18; Person.count = 20; System.out.println(person1.age + " " + Person.count); Person.staticTest(); } }
代码结果:
代码解释:
- 用 static 关键字修饰的成员变量叫做静态成员变量,修饰的成员方法叫做静态成员方法
- 普通成员变量或普通成员方法的访问需要实例化一个对象,通过引用进行访问。但是,静态成员变量或静态成员方法无需创建实例对象,直接通过类名进行访问,格式为:类名.成员变量; 类名.成员方法(实参列表);
- 静态成员变量或方法被同一个类的不同实例所共用,且不属于对象,它们被存放在方法区,只存在一份。
内存分布:
注意:
- 静态方法是不能直接使用非静态成员变量或非静态方法。因为后两者都和实例相关,如果需要使用的话,需要实例化对象,而静态方法和实例无关和类相关,因此不能直接调用。这也就是为什么在 main 函数中调用其他方法,被调用的方法最好是静态方法的原因。
- 那么 main 函数为何非得是静态的呢?不是静态的又会如何?
- 假设 main 函数不是静态的函数,那么想要调用 main 函数,必须要进入 main 函数中,实例化对象,通过引用去调用 main 函数,但问题就在于 main 函数压根就没有被调用,又如何进入到 main 函数当中呢?这就形成了一个逻辑死循环,唯一的解法就在于将 main 函数设置为静态的,通过 Java 虚拟机去调用它。
三、封装
在面向对象编程中,封装是将对象运行所需的资源封装在程序对象中——基本上,是方法和数据。对象是“公布其接口”。其他附加到这些接口上的对象不需要关心对象实现的方法即可使用这个对象。这个概念就是“不要告诉我你是怎么做的,只要做就可以了。”
3.1 private
属性和方法都有自身的访问权限,private/ public 这两个关键字表示 “访问权限控制”
public: public 表明该数据成员、成员函数是对所有用户开放的,所有用户都可以直接进行调用
private: private 表示私有,私有的意思就是除了class自己之外,任何人都不可以直接使用。
在本章第一段代码示例中,成员变量 age 和 name 分别被 public 所修饰,就可能出现以下的问题:
类的使用者必须要了解 Person 类内部的实现, 才能够使用这个类. 学习成本较高。如果 Person 这个类的实现者修改了成员变量的名字,类的使用者就需要将自己的代码随之更改,如果项目的规模较大,就会导致维护的成本过高,
每个成员变量或方法的访问权限是需要依据具体的情况仔细斟酌,而不应当随意的设置为 public。
在这样的思考下,private 关键字显得尤为重要,被其修饰的属性,类的使用者是不能够直接使用的(根本没有访问到),需要借助接下介绍的 getter 和 setter 方法,这样就可以不用对类里面的实现细节进行知晓。
3.2 getter 和 setter
当用 private 来修饰字段的时候,如果需要获取或者修改这个 private 属性,就需要使用 getter 和 setter 方法
代码示例:
class Person { private int age; private String name; public int getAge() { return age; } public void setAge(int myAge) { age = myAge; } public void setName(String myMame) { name = myMame; } public String getName() { return name; } public void show() { System.out.println("姓名: " + name + " 年龄: " + age); } } public class TestDemo { public static void main(String[] args) { Person person1 = new Person(); person1.setAge(18); person1.setName("富春"); int age = person1.getAge(); String name = person1.getName(); System.out.println(name + " " + age); person1.show(); } }
代码结果:
代码解释:
getName 和 getAge 即为 getter 方法, 表示获取这个成员的值
setName 和 setAge 即为 setter 方法, 表示设置这个成员的值
四、构造方法
实例化对象时分两步:
1。为对象分配内存空间
2.调用对象的构造方法(构造方法不止一种)
构造方法是一种特殊方法, 使用关键字new实例化新对象时会被自动调用,不仅可以构造对象,也可以帮助我们对成员变量进行初始化。
4.1 基本语法
规则:
方法名和类名是相同的,并且没有返回值
在类中没有提供任何的构造函数的情况下,编译器会默认生成一个不带有参数的构造函数
如果类中定义了构造方法,就不会默认生成无参的构造方法
构造方法支持重载,规则和普通方法的重载一致
代码示例:
class Person { private int age; private String name; public Person() { System.out.println("不带参数的构造方法"); } public Person(String name) { this.name = name; System.out.println("带一个参数的构造方法"); } public Person(String name,int age) { this.name = name; this.age = age; System.out.println("带两个参数的构造方法"); } public void show() { System.out.println("姓名: " + this.name + " 年龄: " + this.age); } } public class TestDemo { public static void main(String[] args) { Person person1 = new Person(); person1.show(); Person person2 = new Person("富春"); person2.show(); Person person3 = new Person("山居",18); person3.show(); } }
代码结果:
4.2 this 关键字
在此之前的代码中出现了很多的 this 关键字,那么该关键字代表什么呢?
该关键字在对象被构造的过程中被使用,对象还未构造完,因此它并不代表当前对象,this 关键字代表着当前对象的引用,
可以借助 this 关键字来访问对象的成员变量和成员方法,也可以通过它来调用其他的构造方法
方法:
- this . 成员变量
- this . 成员方法
- this ( )
注意:
用 this 关键字调用其他的构造方法时一定要放在第一行静态方法里不允许出现 this 关键字,因为该关键字代表着当前对象的引用,而静态的方法是不依赖于对象的
代码示例:
class Person { private int age; private String name; public Person() { this("富春",18);//调用其他的构造方法 System.out.println("不带参数的构造方法"); } public Person(String name,int age) { this.name = name; this.age = age; System.out.println("带两个参数的构造方法"); } public void show() { System.out.println("姓名: " + this.name + " 年龄: " + this.age); } } public class TestDemo { public static void main(String[] args) { Person person1 = new Person(); person1.show(); } }
代码结果:
加 this 关键字是一个良好的代码习惯。
五、代码块
Java 中用大括号 { } 将多行代码括起来,并形成一个独立的代码区间的代码形式称为代码块,它是 Java 中常见的代码形式。
根据代码块定义的位置以及关键字,又可分为以下四种:普通代码块、构造代码块、静态代码块、同步代码块。
接下来主要向大家介绍前三种,最后一种讲解多线程部分时在涉及一下。
5.1 普通代码块
它是最常见的代码块,是类中方法的方法体或在方法名后面。
代码示例:
public class TestDemo { public static void main(String[] args) { int a = 10; { int b = 20; System.out.println(b); } System.out.println(a); } }
代码解释:
在这里,main 方法后面跟着的 { } 所包裹的内容是一个普通代码块,将定义变量 b 并且打印它的代码包裹起来的 { } 中的内容也是一个普通代码块
5.2 构造代码块
定义在类中的不加修饰符的代码块叫构造代码块也叫实例代码块。构造代码块一般用于初始化实例成员变量
代码示例:
class Person { private int age; private String name; { this.name = "山居"; this.age = 18; } public void show() { System.out.println("姓名: " + this.name + " 年龄: " + this.age); } }
5.3 静态代码块
使用 static定义的代码块,一般用于初始化静态成员属性和需要提前准备的一些数据
代码示例:
class Person { private int age; private String name; public static int count; static { count = 20; } public void show() { System.out.println("姓名: " + this.name + " 年龄: " + this.age); } }
5.4 注意事项
构造代码块优先于构造函数执行静态代码块优先于构造代码块执行,且对于同一个类来说只执行一次当代码块和成员变量同为静态的或同为实例的时候,其值和定义的顺序是有关系的
六、快捷方法
6.1 toString方法
在本章第一段代码示例中,类里面通过 show 方法将对象的属性进行打印,但当属性很多时,就显得不那么方便。因此,可以用快捷键。
步骤一:alt + insert 或者 鼠标右键点一下选择 Generate (要在类的代码区域执行)
步骤二:选择 toString()
步骤三:选择需要打印的属性
步骤四:选择 OK
代码示例:
class Person { public int age; public String name; @Override public String toString() { return "Person{" + "age=" + age + ", name='" + name + '\'' + '}'; } } public class TestDemo { public static void main(String[] args) { Person person1 = new Person(); person1.age = 18; person1.name = "富春"; System.out.println(person1); } }
代码结果:
代码解释:
@Override 是注解,用于解释该方法是重写的方法未重写 toString 方法时,打印 person1,将会是一个地址
当重写 toString 方法时,打印 person1,将会直接调用 toString 方法
6.2 setter / getter 方法
setter / getter 方法也可以使用快捷键自动生成
步骤一:alt + insert 或者 鼠标右键点一下选择 Generate (要在类的代码区域执行)
步骤二:选择 Getter and Setter
步骤三:选择需要该方法的属性
步骤四:选择 OK
代码示例:
class Person { private int age; private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; //age = age;错误 } public String getName() { return name; } public void setName(String name) { this.name = name; } public void show() { System.out.println("姓名: " + name + " 年龄: " + age); } }
代码解释:
自动生成的 setter 方法形参名字和类中的成员属性的名字一样的时候,如果不使用 this , 相当于自赋值。this 表示当前对象的引用
6.3 构造方法(快捷)
当想要快速生成参数个数不同的构造方法时,也有快捷键。
步骤一:alt + insert 或者 鼠标右键点一下选择 Generate (要在类的代码区域执行)
步骤二:选择 Constructor
步骤三:选择需要该方法的属性
步骤四:选择 OK(无参的话,跳过步骤三,直接选择 Select None)
代码示例:
class Person { private int age; private String name; public Person() { } public Person(String name) { this.name = name; } public Person(int age, String name) { this.age = age; this.name = name; } }
总结
本篇文章就到里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!