阿里云【名师课堂】Java面向对象开发3 ~ 6:类与对象
3:类与对象的基本定义
是面向对象设计的核心所在,也是所有概念的基础。类本身属于引用数据类型,因此类的使用牵扯到内存的分配问题。
认识类与对象
类指的是一个共性的概念,而对象指的是一个具体的事物。
因此,在实际的开发过程中吧,一定是要首先产生类,而后才可以产生我们的对象。那么对象的所有行为都一定在类中进行了完整的定义。类中没有定义的功能,对象一定无法实现。
类的组成:
- 方法(操作的行为、定义的功能)
- 属性(变量,描述每一个对象的具体特点)
4:类与对象定义及使用
使用class关键字进行类的定义。
class 类名称 {
属性 ;
属性 ;
······
方法(){} // 此时的方法不在由主类直接调用,而是要通过对象进行调用
}
- 范例:观察定义类操作
class Person { // 定义一个类,注意类名称每个单词首字母大写
String name ; // 属性1,表示人的姓名
int age ; // 属性2,表示人的年龄
public void info() { // 一个方法
System.out.println("name = " + name + " age = " + age)
}
}
在这个类中只是定义了两个属性一个方法,而类中可以定义的属性数量与方法数量都没有限制。在编写时每个方法中的代码尽量不要特别长。
类产生之后是不能直接使用的,如果要使用的话必须要定义对象(实例化)。而对象的定义分为以下两种语法形式:
- 声明并实例化对象:
类名称 对象名称 = new 类名称() ;
- 分步进行对象实例化
- 声明对象:
类名称 对象名称 = null ;
(所有变量在定义时都要有值,类的默认值是空null
) - 实例化对象:
对象名称 = new 类名称() ;
- 声明对象:
引用数据类型的最大特征在于内存的分配操作,而只要出现了关键字new,就有开辟新内存。而内存是不能无限开辟的,所以所谓的性能调优就是调整的内存问题。
- 范例:声明并实例化对象
class Person { // 定义一个类,注意类名称每个单词首字母大写
String name ; // 属性1,表示人的姓名
int age ; // 属性2,表示人的年龄
public void info() { // 一个方法
System.out.println("name = " + name + " age = " + age)
}
}
public class TestDemo { // 定义一个程序类
public static void main(String args[]) {
// 类名称 对象名称 = new 类名称() ;
Person per = new Person() ; // 这时就实例化了一个per对象
}
}
所有的对象只有实例化之后才可以真正使用,而对象的使用都是围绕着类进行的,那么此时有两种形式:
- 调用类中的属性:
对象.属性 = 内容 ;
- 调用类中的方法:
对象.方法() ;
实例:观察一个最基本的类的定义以及对象的使用操作形式。
class Person { // 定义一个类,注意类名称每个单词首字母大写
String name ; // 属性1,表示人的姓名
int age ; // 属性2,表示人的年龄
public void info() { // 一个方法
System.out.println("name = " + name + " age = " + age) ;
}
}
public class TestDemo { // 定义一个程序类
public static void main(String args[]) {
// 类名称 对象名称 = new 类名称() ;
Person per = new Person() ; // 这时就实例化了一个per对象
per.name = "Dexter" ; // 设置per对象中的name属性
per.age = 20 ; // 设置per对象中的age属性
per.info() ;
// 输出:name = Dexter age = 20
}
}
5:对象内存分析
想要知道对象的产生分析,首先必须清楚引用类型。引用类型指的是内存空间的操作。重点在两块内存空间:
堆
内存空间:保存真正的数据,对象的属性信息;栈
内存空间:保存堆内存的地址,简单理解:保存的是对象名称
声明并实例化对象的内存分析
上一个实例程序的内存对象分析图解。new在堆内存中开辟了新的堆内存来保存属性(最初是初始值),这个堆内存的地址(图中OX0001)被保存在栈内存中,可以理解为栈内存中保存的就是对象名,因为通过对象名.类名可以修改堆内存中属性的值。
声明并实例化一个对象的格式在这里分析结束,下面分析分步进行对象实例化。
分步进行对象实例化的内存分析
- 实例:分步进行对象实例化
class Person { // 定义一个类,注意类名称每个单词首字母大写
String name ; // 属性1,表示人的姓名
int age ; // 属性2,表示人的年龄
public void info() { // 一个方法
System.out.println("name = " + name + " age = " + age) ;
}
}
public class TestDemo { // 定义一个程序类
public static void main(String args[]) {
// 类名称 对象名称 = new 类名称() ;
Person per = null ; // 声明一个新的对象per
per = new Person() ; // 实例化per对象
per.name = "Dexter" ; // 设置per对象中的name属性
per.age = 20 ; // 设置per对象中的age属性
per.info() ;
// 输出:name = Dexter age = 20
}
}
观察内存分析图:
注意:对象(乃至所有的引用数据类型:数组、类、接口)必须在其开辟空间后才可以使用。如果使用了未开辟空间的引用数据类型,虽然编译时不会报错,但是会在执行时出现NullPointerException:
- 范例;观察一个错误代码:
class Person { // 定义一个类,注意类名称每个单词首字母大写
String name ; // 属性1,表示人的姓名
int age ; // 属性2,表示人的年龄
public void info() { // 一个方法
System.out.println("name = " + name + " age = " + age) ;
}
}
public class TestDemo { // 定义一个程序类
public static void main(String args[]) {
// 类名称 对象名称 = new 类名称() ;
Person per = null ; // 声明一个新的对象per
per.info() ;
}
}
错误出现在第13行,是per
对象调用Person
类中的info
方法。因为只声明对象而没有实例化对象,只在栈空间开辟内存而没有在堆空间开辟内存,所以无法使用这个对象,当然也不能调用类中的方法。
6:引用传递初次分析(重点)
引用传递通俗理解:一个人的大名、小名、外号等,这些别名放在栈内存之中,人在堆内存之中。即:一块堆内存可以被多个栈内存所指向。如果这个人的某样东西(类的属性、方法)丢失了,那么所有别名指向的这样东西都丢失(都无法调用)。
范例:观察引用传递
class Person { // 定义一个类,注意类名称每个单词首字母大写
String name ; // 属性1,表示人的姓名
int age ; // 属性2,表示人的年龄
public void info() { // 一个方法
System.out.println("name = " + name + " age = " + age) ;
}
}
public class TestDemo { // 定义一个程序类
public static void main(String args[]) {
// 类名称 对象名称 = new 类名称() ;
Person per1 = new Person() ;
per1.name = "Dexter" ;
per1.age = 20 ;
per1.info() ;
// 此步骤就是引用传递的操作
Person per2 = per1 ; // 采用同样的类型接收
per2.name = "tsukishima kei" ;
per1.info() ;
per2.info() ;
}
}
对象per1和per2都是类Person的外号,都指向Person。通过二者任意一个调用Person中属性,Person属性都会得到修改。
观察内存分析图
范例:还是观察引用传递
class Person { // 定义一个类,注意类名称每个单词首字母大写
String name ; // 属性1,表示人的姓名
int age ; // 属性2,表示人的年龄
public void info() { // 一个方法
System.out.println("name = " + name + " age = " + age) ;
}
}
public class TestDemo { // 定义一个程序类
public static void main(String args[]) {
// 类名称 对象名称 = new 类名称() ;
Person per1 = new Person() ;
per1.name = "Dexter" ;
per1.age = 20 ;
per1.info() ;
Person per2 = new Person() ; // 有new就会开辟新的内存空间
per2.name = "toono takaki" ;
per2.age = 14 ;
per2.info() ;
per2 = per1 ; // 已在main定义了变量 per2,不需要再加上Person
per2.name = "tsukishima kei" ;
per1.info() ;
per2.info() ;
}
}
观察内存分析图:
垃圾内存空间:没有任何栈内存指向的堆内存空间,所有的垃圾空间将不定期被Java中的Garbage Collector回收以实现内存空间的释放。不过从实际开发来讲,虽然Java提供有GC,但是GC也会造成程序性能的下降。所以开发过程中一定要控制好对象的产生数量,即:无用的对象尽可能少产生。