版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Top1. 对象和类(上)1. 对象和类(上)1.1. 面向对象程序设计1.1.1. 面向过程的结构化程序设计首先来看一个需求,实现员工信息管理,将员工简历信息中的数据:姓名、性别、年龄、薪水, 存储在信息管理系统中进行操作。可以定义一个输出雇员信息的方法进行数据的输出,传递4个参数,代码如下:1. /* 打印员工信息的方法 */2. public static void printEmpInfo(String name,int age, 3. char gender,double salary) 4. System.out.println("-");5. System.o
2、ut.println("姓名: " + name);6. System.out.println("年龄:" + age);7. System.out.println("性别:" + gender);8. System.out.println("薪水:" + salary);9. 在main() 方法中声明雇员信息数据(分别为4个变量), 然后调用如上的输出雇员方法进行数据的输出,当提升工资后,再调用输出方法输出,代码如下:1. /* 打印雇员信息 */2. public static void main (Stri
3、ng args )3. /雇员14. String emp1Name = "黄河大虾"5. int emp1Age = 25;6. char emp1Gender = '男'7. double emp1Salary = 8000.00;8. 9. /打印员工信息10. printEmpInfo(emp1Name, emp1Age, emp1Gender, emp1Salary);11. 12. /修改员工工资(增长20%)并打印13. emp1Salary *= 120.0 / 100.0;14. print
4、EmpInfo(emp1Name, emp1Age,emp1Gender, emp1Salary);15. 如上代码的实现方式即为面向过程的结构化程序设计, 何为面向过程?面向过程是一种以过程为核心的编程思想,即分析出解决问题所需要的步骤,然后使用方法将这些步骤一步一步的实现,使用的时候,在main方法中一个一个依次调用就可以了。分析如上代码,看看结构化程序的弊端所在,首先,如上代码缺乏对数据的封装,变量emp1Name,emp1Age,emp1Gender,emp1Salary为4个完全独立的变量, 并不是一个整体。其次,数据和方法(对数据的操作)的分离,在打印雇员信息方法中,传递了4个参数
5、,而这4个参数与在main方法中所定义的4个变量并无直接关系。这就是面向过程程序设计的弊端,那如何解决?使用面向对象的程序设计。1.1.2. 什么是抽象数据类型面向对象的第一步就是抽象数据类型,所谓抽象数据类型可以理解为:将不同类型的数据的集合组成个整体用来描述一种新的事物。像如上程序中,可以将姓名、年龄、性别、工资这4个不同类型的数据组成一个整体来描述雇员这个新事物。1.1.3. 什么是类类定义了一种抽象数据类型,而类不但定义了抽象数据类型的组成(成员变量),同时还定义了对该类型可以实施的操作(方法)。看如下代码定义了雇员类:1. /* 定义雇员类 */2. public class Emp
6、3. String name;4. int age;5. char gender;6. double salary;7. 在如上的实例代码中,仅仅定义了Emp类型的组成,即成员变量。该类定义了4个成员变量:String类型的name用于存放名字;int类型的age用于存放年龄;char类型的gender用于存放性别;double类型的salary用于存放工资。这个时候printEmpInfo()方法的参数也可以进行修改了, 可以将其改为Emp类型(Emp是一种抽象数据类型),这样可以看出是将一个雇员信息当作了一个整体来操作,看如下代码:1. public static void printEm
7、pInfo(Emp emp) 2. System.out.println("-");3. System.out.println("姓名: " + );4. System.out.println("年龄:" + emp.age);5. System.out.println("性别:" + emp.gender);
8、6. System.out.println("薪水:" + emp.salary);7. 当调用如上方法时,需要传递一个Emp类型的数据,称之为Emp类型的对象。每个Emp类型的对象都包含name、age、gender和salary四个成员,通过“.”的方式进行访问。下面看一下在main ()方法中的调用代码:1. public static void main(String args) 2. Emp emp1 = new Emp(); /使用new关键字创建Emp类型的对象3.
9、; = "黄河大虾"4. emp1.age = 25;5. emp1.gender = '男'6. emp1.salary = 8000; /为该对象的各个成员变量赋值7.8. printEmpInfo(emp1);9. emp1.salary *= 120.0 / 100.0;10.
10、60; printEmpInfo(emp1); /使用该对象调用printEmpInfo方法11. 分析如上几段代码可以看出,定义了Emp类以后,提升了代码的模块化以及代码的重用性,但程序依然存在问题,即:打印信息的方法是只针对Emp数据的操作,属于Emp自身的方法,需要实现数据和方法(对该类数据的操作)的统一,也就是说,可以将打印信息的方法也放在Emp中定义,修改后的完整代码如下所示:1. /*进一步修改后的雇员类*/2. public class Emp3. String name;4. int age;5. char gender;6. double salary;
11、7.8. /*打印信息的方法*/9. public void printInfo() /定义在类中,可直接对成员变量进行操作10. System.out.println("-");11. System.out.println("姓名: " + name);12. System.out.println("年龄:" + age);13. System.out.println("性别:" + gender);14. System.out.println("薪水:" + salary);15. 16.
12、17. /*针对修改后的Emp类的使用方式*/18. public class EmpManager 19. public static void main(String args) 20. Emp emp2 = new Emp();21. = "白发馍女"22. emp2.age = 24;23.
13、60; emp2.gender = '女'24. emp2.salary = 6000;25. /*调用方法打印信息*/ /创建完Emp对象后,对其成员变量赋值,然后调26. emp2.printInfo(); /用其printInfo()方法打印各个成员变量信息27. &
14、#160; emp2.salary *= 125.0 / 100.0;28. emp2.printInfo(); 29. 30. 通过上面的代码,很好的实现了对数据的封装,并且实现了数据与方法的统一。这种方式即为面向对象方式,即:以对象为中心来构建软件系统。1.2. 定义一个类1.2.1. 定义类的成员变量类是一种引用数据类型。类为对象的模板,简单的说就是分类。类的定义包括
15、“成员变量”的定义和“方法”的定义,其中“成员变量”用于描述一类对象共同的数据结构。在Java语言中,类的成员变量的定义可以使用如下语法:1. class 类名 2. 成员变量类型 变量名称;3. 4. 定义好类之后,可以创建该类的对象,对象创建之后,其成员变量可以按照默认的方式初始化;对象成员变量的默认初始化值规则如下图 - 5所示:图- 51.2.2. 定义类的方法类中除了定义成员变量,还可以定义方法,用于描述对象的形为,封装对象的功能。在Java语言中,可以按照如下方式定义类中的方法:1. class 类名 2. 返回值类型 方法名称(参数列表) 3. 方法体4.
16、; 5. 6. 下面,通过案例对成员方法进行演示,需求:为方块类定义drop()方法如下所示:1. class Cell 2. int row ; int col ;3. /*方块下落的方法*/4. public void drop ( ) 5. row +;
17、160; /行+,即下落6. 7. 调用方法,也和访问成员变量一样,通过“.”符号,代码如下:1. /* 创建方块类对象,调用下落方法,并打印效果*/2. class TestCell 3. public static void main(String args)4. System.out.println("-绘制Cell-");5. Cell cell = new Cell();6. cell.row = 15;7
18、. cell.col = 6;8. printCell(cell);9. 10. System.out.println("-Cell下落一行-");11. /调用drop方法,下落一行12. cell.drop();13. printCell(cell); 14. 1
19、5. 1.3. 创建并使用对象1.3.1. 使用new关键字创建对象类定义完成后,可以使用new关键字来创建对象。new运算的语法为: new 类名();此创建对象的过程也通常称为实例化。javax.swing.JFrame是JDK提供的一个类,用于封装显示在桌面上的一个窗体。使用new JFrame()可以创建一个窗体对象,如下图 1所示:图- 11.3.2. 引用类型变量为了能够对实例化的对象进行访问控制,需一个特殊的变量,即引用。对引用有两点需要说明:1. 引用类型变量可以存储该类对象的地址信息,通常称为“指向该类的对象”,当一个引用类型变量指向该类的对象,就可以通过这个变量对对象实施访
20、问。2. 除8种基本类型之外,用类、接口、数组等声明的变量都称为引用类型变量,简称“引用”。可以看图 3,描述了类、对象、引用之间的关系:图- 3当创建了引用类型变量之后,就可以通过引用来访问对象的成员变量或调用方法,如下代码所示:1. Emp emp = new Emp();2. =“黄河大侠”; /访问对象的成员变量3.4. JFrame frame = new JFrame();5. frame.setSize(200,300); /调用方法. 访问对象的成员变量、调用方法当创建了引用后,即可以通过引用来访问对象的成员变量,以及调用方法。看如下的示例:1.
21、Cell c = new Cell();2. c.row = 2;3. c.col = 3; /访问成员变量4. c.drop();5. c.moveLeft(2);6. String str = c.getCellInfo(); /调用方法1.3.4. 引用类型变量的赋值引用类型变量存储的是对象的地址信息, 对引用类型变量的赋值, 除了使用上面的new关键字以外,还可以有另外一种赋值方式, 即:相同类型的引用类型变量之间相互赋值。 需要注意的是:引用类型变量之间的赋值不会创建新的对象,但有可能会使两个以上的引用指向同一个对象。 请看如下代码:1. Emp e1 = new Emp();2.
22、Emp e2 = e1; /将e1的值(对象的地址信息)赋给e2,e2和e1指向相同的对象。 3. =“黄河大虾”;4. = “白发馍女”;5. System.out.println(); 如上代码的输出结果为:白发馍女。因为e1与e2存储的地址相同,也就意味着e1与e2指向了同一个对象,那么对该对象的修改,将会影响所有对该对象的引用。1.3.5. null和NullPointerException对于引用类型变量,除了上面的两种赋值方式之外,还可以对其赋值为null。null的含义为“空”,表示还没有指向任何对象。例如:1. Emp emp =
23、null; /引用emp中的值为null,没有指向任何对象; 2. emp = new Emp(); /引用emp指向了一个Emp对象; 需要注意:当一个引用的值为null的时候,如果通过引用访问对象成员变量或者调用方法是不合逻辑的(因其没有指向某对象,自然不会有属性和方法)。此时,会产生NullPointerException(空指针异常)。异常的详细概念后面详细讲。请看下面的代码,将就产生NullPointerException:1. JFrame frame = null;2. frame.setSize(200,300);Top1. 对象和类(下)2. 数组1. 对象和类(下)1.1.
24、 方法的重载1.1.1. 方法的签名方法的签名包含如下两个方面:方法名和参数列表。Java语法规定,一个类中不可以有两个方法签名完全相同的方法,即:一个类中不可以有两个方法的方法名和参数列表都完全相同,但是,如果一个类的两个方法只是方法名相同而参数列表不同,是可以的。下面看如下代码:1. public class Cashier 2. public boolean pay(double money) 3. public boolean pay(double money) 4. 分析如上代码,结论会出现编译错误,因为在同一个类Cashier中的两个方法,签名相同,这在java语法中是不允许出现的
25、。而下面的代码就是正确的:1. public class Cashier 2. public boolean pay(double money) 3. public boolean pay(String cardId,4. String cardPwd) 5. 可以看到上面的代码,在类Cashier中,虽然pay方法名相同,但是参数列表不同,这样是被允许的,可以正常编译通过。1.1.2. 方法重载及其意义假想收款窗口的设计,可以采用两种方式:1. 开设三个窗口,分别用来接收现金,信用卡和支票的交付方式(分别在窗口上标明),用户根据需要选择窗口,并投入指定的物件,如图 8所示:图- 81. 开设
26、一个窗口,标为“收款”,可以接收现金,信用卡和支票三种物件。该窗口可以按照输入的不同物件实施不同的操作。例如,如果输入的是现金则按现金支付,如果输入的是信用卡则按信用卡支付,以此类推,如图 9所示。图- 9通过对如上两种方式的分析,请问:哪种方式更好一些呢?常规情况下认为,相对于A的方式,B的设计可以降低用户的负担,用户去付款时不需要去找对应的窗口,只需要到收款窗口就可以了, 减少了用户使用时的错误,B的设计更加优雅一些。按B的设计方式即为方法重载,在Java语言中,允许多个方法的名称相同,但参数列表不同,此种方式称为方法的重载(overload)。下面的代码即为收款窗口的两种设计方式,可以看
27、出B方式即为方法的重载方式。1. public class PayMoney /-A方式2. payByCash(double money) 3. payByCard(String cardId,StringcardPwd) 4. payByCheck(String compayName,double money) 5. 6. public class PayMoney /-B方式7. pay(double money) 8. pay(String cardId,StringcardPwd) 9. pay(String compayName,double money) 10. 通过如上的代码可
28、以看出,按照A的方式若想付款,需在三个方法之中进行选择,不同的方法即为不同的付款方式,而B的方式即为重载方式,若想付款,只需要找到pay方法,只不过,传递不同的参数即可。1.1.3. 编译时根据签名绑定调用方法当调用重载的方法时,编译器会在编译时根据签名的不同来绑定调用不同的方法,可以把重载的方法看成是完全不同的方法,只不过,恰好方法名称相同而已。请看下面的两组代码:重载方法:1. pay(double money) 2. pay(String cardId,StringcardPwd) 3. pay(String compayName,double money) 调用方法:(只管调用即可,由
29、编译器来根据签名绑定不同的方法)1. pay(8888.88);2. pay(“12345678”,”666666”); 3. pay( “tarena”, 8888.88);1.2. 构造方法1.2.1. 构造方法语法结构构造方法是在类中定义的方法, 但不同于其他的方法,构造方法的定义有如下两点规则:1. 构造方法的名称必须与类名相同。2. 构造方法没有返回值,但也不能写void。如下所示为构造方法的语法:1. 【访问修饰符】类名( ) 2. /构造方法体3. 1.2.2. 通过构造方法初始化成员变量Java语言中的构造方法常常用于实现对对象成员
30、变量的初始化,如下代码展示了构造方法的使用。1. class Cell 2. int row ;3. int col ; 4. public Cell (int row1 , int col1)5. row = row1; 6. col = col1;7. 8. 9. class TestCell 10. public static void main(String args )11. Cell c1 = new Cell( 15 , 6 );12.
31、 printCell(c1);13. 14. 可以看出,在创建对象时,构造方法写在new关键字之后,可以理解为:“new”创建了对象,而构造方法对该对象进行了初始化。1.2.3. this关键字的使用在上面的代码中,为该构造方法定义了两个参数,分别表示行和列。为了区分于Cell类的成员变量row和col,为两个参数分别取名为row1和col1,这显然不是一种好方法,因为,我们会希望依然使用变量row来表示行,col来表示列,而不是row1和col1。为了解决这个问题,需要使用到this关键字。this关键字用在方法体中,用于指代调用该方法的当前对象,简单的说:哪个对象调用方法,this指的就是
32、哪个对象。严格来讲,在方法中需要通过this关键字指明当前对象。请看如下代码:1. public void drop ( ) 2. this.row +; 3. 上面的drop()方法可以解释为:将调用该方法对象的成员变量的row加1。很多时候,为了方便起见,在没有歧义的情况下可以省略this,如下所示:1. public void drop ( ) 2. row +; 3. 在构造方法中,用来初始化成员变量的参数一般和成员变量取相同的名字,这样会有利于代码的可读性,但此处就必须通过this关键字来区分
33、成员变量和参数了,而不能省略this了,如下代码所示:1. public Cell (int row , int col ) 2. this . row = row ;3. this . col = col ;4. 如上的代码中,this.row表示的为Cell类的成员变量,而row为参数变量。1.2.4. 默认的构造方法JAVA语法规定,任何一个类都必须含有构造方法,假如源程序中没有定义,则编译器在编译时将为其添加一个无参的空构造方法(此方法称之为“默认的构造方法”)。例如:先前所定义的Cell类
34、源文件中没有写构造方法,但也可以编译成功,因为在编译时由编译器为其添加了如下的构造方法:1. Cell( ) 但是有一个问题需要注意,当类定义了构造方法后,Java编译器将不再添加默认的构造方法,看如下代码:1. class Cell2. int row; 3. int col;4. Cell (int row,int col)5. this.row = row;6.
35、 this.col = col;7. 8. 9. public class CellGame 10. public static void main(String args) 11. Cell cell = new Cell( ); /编译错误12. 13. 可以看出,在创建Cell类对象时,发生了一个编译期错误,那是因为,在Cell类中已经定义了Cell(int,int)的构造方法,此时,编译器将不会再提供无参的构造方法了。所以此处发生了编译期错误。1.2.5. 构造方法的重载很多时候,
36、为了使用的方便,可以对一个类定义多个构造方法,这些构造方法都有相同的名称(类名),只是方法的参数不同,称之为构造方法的重载。在创建对象时,Java编译器会根据不同的参数调用来不同构造方法。看如下的几组构造方法的声明及调用。1. 声明:2. Cell ( int row , int col ) 3. 4. 调用:5. Cell c1 = new Cell ( 5 , 6 );6.7. 声明:8. Cell ( ) 9. 10. 调用:11. Cell c1 = new Cell ( ) ;12.13. 声明:14. Cell (int row) 15. this(row , row );16.
37、17. 调用:18. Cell c1 = new Cell ( 5 ) ;可以注意到,在第三段声明的构造方法中,使用了this关键字,在构造方法中可以通过this关键字来调用另外的一个重载的构造方法。this(row,row)调用了第一段声明Cell(int row, int col)构造方法。2. 数组2.1. 引用类型数组2.1.1. 数组是对象在java中,数组属于引用数据类型,数组对象存放在堆中存储,数组变量属于引用类型,存储数组对象的地址信息,指向数组对象。而数组的元素可以看成数组对象的成员变量(只不过类型全部相同)。看如下代码:1. int arr = new int 3 内存的分
38、配如下图 4所示:图- 4说明: 在堆内存中分配了数组对象,分配三个int型空间,并将每个元素赋初始值为0,栈中存储对堆中数据的引用,即堆中int数组的首地址。2.1.2. 引用类型数组的声明刚刚声明的数组为基本类型数组,除了基本类型数组以外,也可以声明引用类型数组。所谓引用类型数组,即数组元素的类型不是基本类型(int,char,float。) , 而是引用类型,看如下代码:1. Cell cells = new Cell 4 ;其内存分配如下图 5所示:图- 5从上图示可以看出,new Cell4实际是分配了4个空间用于存放4个Cell类型的引用,并赋初始值为null,而并非是分配了4个C
39、ell类型的对象。2.1.3. 引用类型数组的初始化前面所介绍的基本类型数组的默认值同成员变量默认的初始值(如int类型的数组初始值为0),而引用类型数组的默认初始值都是null。如果希望每一个元素都指向具体的对象,则需要针对每一个数组元素进行“new”运算。与基本类型数组一样,也可以采用静态初始化的方式进行初始化操作。如下代码所示:1. Cell cells = new Cell4;2. cells0 = new Cell(0,4);3. cells1 = new Cell(1,3);4. cells2 = new Cell(1,4);5. cells3 = new Cell(1,5);等价
40、于:1. Cell cells = new Cell 2. new Cell(0,4) ,3. new Cell(1,3) ,4. new Cell(1,4) , 5. new Cell(1,5) 6. ;如上数组内存分配图如下图 6 所示:图- 62.1.4. 数组的类型是基本类型数组前面所介绍的数组的元素或为基本类型int,或为引用类型Cell,而数组本身也是一种数据类型,当然也可以作为数组的元素。看
41、下面的代码:1. int arr = new int3 ;2. arr0 = new int2;3. arr1 = new int3;4. arr2 = new int2;5. arr11 = 100;分析如上代码可以看出,变量arr指向一个数组,该数组有三个元素,每个元素都是int类型数组,长度分别为2,3,2,arr11=100表示将arr数组中的第2个元素(数组)的第2个元素赋值为100, 其内存分配如图 7所示:图- 7对于元素为数组的数组,如果每个数组元素的长度相同,也可以采用如下的方式声明:1. int row = 3, col = 4;2. int arr = new intro
42、wcol;3. for (int i = 0; i < row; i+) 4. for (int j = 0; j < col; j+) 5. arrij = i * j;6. 7. 如上形式的数组可以用来表示类似“矩阵”这样的数据结构(3行4列),如下图-8所示,arrij 可以认为访问行号为i,列号为j的那个元素。在其他的一些语言中有专门表示这样结构的所谓二维数组;但严格的讲,Java语言中没有真正的二维数组。图- 8Top1. 对象内存管理2. 继承的意义(上)1. 对象内存管理1.1. 对象内存管理1.1.1. 对象内存管理在JAVA中,有java程序、虚拟机、操作系统三个
43、层次,其中java程序与虚拟机交互,而虚拟机与操作系统交互。编译好的java字节码文件运行在JVM中。程序中无论代码还是数据,都需要存储在内存中,而java程序所需内存均由JVM进行管理分配,开发者只需关心JVM是如何管理内存的,而无需关注某种操作系统是如何管理内存的,这就保证了java程序的平台无关性。JVM会将申请的内存从逻辑上划分为三个区域:堆、栈、方法区。这三个区域分别用于存储不同的数据。1.2. 堆内存1.2.1. 对象存储在堆中JVM在其内存空间开辟了一个称为“堆”的存储空间,这部分空间用于存储使用new关键字所创建的对象。请看如下代码:1. Cell c = new Cell (
44、);其内存分布如图 1所示:图- 1从图示1中可以看到右侧的堆内存,new Cell()所创建的对象在堆中分配,同时成员变量亦在此分配,并赋初始值为零。引用类型变量c在栈内存中分配,其中保存的数据,为对象在堆内存中的地址信息,假设对象在堆内存的地址为40DF,则c中保存的即是40DF。1.2.2. 成员变量的生命周期当声明好对象之后,对该对象(堆中的Cell)的访问需要依靠引用变量(栈中的c),那么当一个对象没有任何引用时,该对象被视为废弃的对象,属于被回收的范围,同时该对象中的所有成员变量也随之被回收。可以这样认为,成员变量的生命周期为:从对象在堆中创建开始到对象从堆中被回收结束。请看如下的
45、代码,演示了对象不再被引用:1. Cell c = new Cell();2. c = null ;当将c赋值为null时,表示c不再指向刚刚分配的对象空间,此时成员变量失效。1.2.3. 垃圾回收机制垃圾回收器(Garbage Collection,GC)是JVM自带的一个线程(自动运行着的程序),用于回收没有任何引用所指向的对象。GC线程会从栈中的引用变量开始跟踪,从而判定哪些内存是正在使用的,若GC无法跟踪到某一块堆内存,那么GC就认为这块内存不再使用了,即为可回收的。但是,java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。1.2.4. Java程序的内存泄露问题内存泄露是指
46、,不再被使用的内存没有被及时的回收,严重的内存泄露会因过多的内存占用而导致程序的崩溃。在程序中应该尽量避免不必要的内存浪费。GC线程判断对象是否可以被回收的依据是该对象是否有引用来指向,因此,当确定该对象不再使用时,应该及时的将其引用设置为null,这样,该对象即不再被引用,属于可回收的范围。1.2.5. System.gc()方法GC的回收对程序员来说是透明的,并不一定一发现有无引用的对象就立即回收。一般情况下,当我们需要GC线程即刻回收无用对象时,可以调用System.gc()方法。此方法用于建议JVM马上调度GC线程回收资源,但具体的实现策略取决于不同的JVM系统。1.3. 非堆-栈1.
47、3.1. 栈用于存放方法中的局部变量JVM在其内存空间开辟一个称为”栈”的存储空间,这部分空间用于存储程序运行时在方法中声明的所有的局部变量,例如,在main方法中有如下代码:1. Cell c = new Cell ( );2. int num = 5;其内存分配如图 2 所示:图- 2说明:方法中的变量即为局部变量,是在栈内存中分配,若变量为值类型,则在栈中存储的就是该变量的值。若变量为引用类型,则在栈中存储的是堆中对象的地址。1.3.2. 局部变量的生命周期一个运行的Java程序从开始到结束会有多次方法的调用。JVM会为每一个方法的调用在栈中分配一个对应的空间,这个空间称为该方法的栈帧。
48、一个栈帧对应一个正在调用中的方法,栈帧中存储了该方法的参数、局部变量等数据。当某一个方法调用完成后,其对应的栈帧将被清除,局部变量即失效。1.3.3. 成员变量和局部变量成员变量与局部变量的差别如下:局部变量:1) 定义在方法中;2) 没有默认值,必须自行设定初始值;3) 方法被调用时,存在栈中,方法调用结束时局部变量从栈中清除;成员变量:1) 定义在类中,方法外;2) 由系统设定默认初始值,可以不显式初始化;3) 所在类被实例化后,存在堆中,对象被回收时,成员变量失效;1.4. 非堆-方法区1.4.1. 方法区用于存放类的信息方法区用于存放类的信息,Java程序运行时,首先会通过类装载器载入
49、类文件的字节码信息,经过解析后将其装入方法区。类的各种信息(包括方法)都在方法区存储,看如下代码:1. Cell c = new Cell();程序在执行这句话时,Cell类首先被装载到JVM的方法区,其中包括类的基本信息和方法定义等,如下图 3 所示:图- 3通过图示可以看出,在方法区中,包含Cell类的字节码文件,及类的基本信息及方法drop等。1.4.2. 方法只有一份当类的信息被加载到方法区时,除了类的类型信息以外,同时类内的方法定义也被加载到方法区;类在实例化对象时,多个对象会拥有各自在堆中的空间,但所有实例对象是共用在方法区中的一份方法定义的。意味着,方法只有一份。看如下代码:1.
50、 JFrame f1 = new JFrame(); 2. JFrame f2 = new JFrame(); 3. f1.setSize(200, 300);4. f2.setSize(300,400); 如上的代码中,对象有两个,但是setSize方法只有一份,分别针对f1指向的对象和f2指向的对象调用了两次。2. 继承的意义(上)2.1. 继承2.1.1. 泛化的过程前面的案例中定义了T类和J类, 通过分析可以发现, 在这两个类中存在着大量的重复代码,像cells属性、print方法、drop方法、moveLeft方法、moveRight方法,在这两个类中都存在,并且实现上基本也是相同的
51、,本着代码重用的原则,可以使用继承的方式来实现。首先,构建T类和J类的父类Tetromino类,将公共的(T类和J类公有的)信息存放在父类中, T类和J类继承Tetromino父类。此时,子类即可以共享父类的数据。这个过程就是泛化的过程。2.1.2. extends关键字使用继承可以实现代码的重用,在java语言中,需要通过extends关键字实现类的继承。继承完成后,子类(Sub class)可以继承父类(Super class)的成员变量及成员方法,同时子类也可以定义自己的成员变量和成员方法。届时,子类将具有父类的成员及本类的成员。需要注意的是,Java语言不支持多重继承,即:一个类只能继
52、承一个父类,但一个父类可以有多个子类。看下面的代码:1. public class Tetromino 2. Cell cells;3. public Tetromino() 4. cells = new Cell4;5. 6. public void drop() /同写过的T类 7.
53、; public void moveLeft() /同写过的T类8. public void moveRight() /同写过的T类9. public void print() /同写过的T类10. 11. public class TetrominoT extends Tetromino 12. public TetrominoT(int row, int col) 13.
54、60; cells0 = new Cell(row, col);14. cells1 = new Cell(row, col + 1);15. cells2 = new Cell(row, col + 2);16. cells3 = new Cell(row + 1, col
55、+ 1); 17. 18. 如上代码说明:声明父类Tetromino,将公共信息放在其中,包括Cell声明、drop()方法、moveLeft()方法、moveRight()方法,print()方法。声明无参构造函数,对成员变量Cell数组进行实例化。声明子类TetrominoT继承Tetromino,并声明有参构造函数,传递行row,列col参数,进行T型数组元素的初始化。下面在main方法中,声明一个T型对象,即可以实现T型对象的构建:1. TetrominoT t = new TetrominoT( 1 , 1);上面的代码,在创建子类对象
56、时,调用了子类的有参构造函数进行数据的初始化,试想下,父类Tetromino的无参构造函数执行了吗?通过分析可以肯定的是,父类的无参构造函数被执行了。在程序中并没有声明父类的构造函数,那它是如何执行的呢?2.1.3. 继承中构造方法父类的无参构造方法之所以被执行,是因为java规定,子类在构造之前必须先构造父类。事实上,子类的构造方法中是必须要通过super关键字来调用父类的构造方法的,这样才可以保证妥善的初始化继承自父类的成员变量。但是看上一个案例中的代码并没有super调用父类构造方法,那是因为,如果子类的构造方法中没有调用父类的构造方法,则java编译器会自动的加入对父类无参构造方法的调
57、用。请看如下代码,演示了super关键字的用法:1. public TetrominoT(int row, int col) 2. super ( ) ; 3. cells0 = new Cell(row, col);4. cells1 = new Cell(row, col + 1);5. 6. 上面的代码中,super();为编译器自动加入的,并且super关键字必须位于子类构造方法的第一行,否则会有
58、编译错误。另外一点需要注意的是,若父类没有提供无参的构造方法,则会出现编译错误。请看如下的示例:1. class Foo /父类2. int value;3. Foo(int value) 4. this.value = value;5. 6. 7. class Goo extends Foo /子类8. int num;9. Goo(int num) 10. this.num = num;11. 12. 分析上面的代码,在子类构造方法中没有写super调用父类构造方法,这时编译器会默认添加super()来调用父类的无参构造方法,但是父类中又没有定义无参的构造方法,因此会发生编译错误。针对上面
59、的问题,可以有两种解决方案,方案一为在父类中添加无参的构造方法,方案二为在子类构造方法中显示调用父类的有参构造方法(常常使用),这样可以保证父类的成员变量均被初始化,参见下面的代码:1. class Goo extends Foo 2. int num;3. Goo(int value, int num) 4. super(value);5. this.num = num6. 7. 如上的代码,在子类中调用了父类的构造方法,初始化了继承自父类的value成员变量,编译正确。2.1.4. 父类的引用指向子类的对象一个子类的对象可以向上造型为父类的类型。即,定义父类型的引用可以指向子类的对象。看如下代码所示:1. class Foo 2. int value;3. public void f() 4. Foo(int value) 5. this.value = value;6. 7. 8. class Goo extends Foo 9. in
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 二零二五年度农产品代加工与农业绿色生产合作合同3篇
- 2025年度全新员工离职保密协议及知识产权归属合同2篇
- 二零二五年度互联网医疗股东股权变更及服务协议3篇
- 二零二五年度文化场馆租赁合同范本3篇
- 二零二五年度环保材料研发人员劳动合同书(含成果转化)2篇
- 2025年公司法人变更合同审查与合规性审查专项服务3篇
- 二零二五年度环保设备检修及保养协议3篇
- 二零二五年度农产品电商运营委托收购合作协议3篇
- 2025养生馆合伙人生态养生旅游项目合作协议3篇
- 二零二五年度农机作业与农村环境保护服务合同3篇
- 2024秋新商务星球版地理7年级上册教学课件 第5章 地球表层的人文环境要素 第3节 世界文化的多样性
- 人教版三年级数学上册 期末测试
- 《跨境电子商务基础》课件-阿里巴巴国际站概述
- 政治-湖南省名校教育联盟2025届高三12月大联考试题和答案
- 2025年上半年四川省成都市大数据中心招聘3人易考易错模拟试题(共500题)试卷后附参考答案-1
- 外研版一年级上册新交际英语(2024)全册教案(单元整体教学设计)
- 国家安全概论学习通超星期末考试答案章节答案2024年
- 翻译技术实践智慧树知到期末考试答案章节答案2024年山东师范大学
- 国家开放大学电大本科《西方社会学》2023-2024期末试题及答案(试卷代号:1296)
- JBT5323-91立体仓库焊接式钢结构货架 技术条件
- 60m3卧式液化石油气储罐设计
评论
0/150
提交评论