学习主线:
1、Java类及类的成员:属性、方法、构造器(前三个用的多)、代码块、内部类
2、面向对象的三大特征:封装性、继承性、多态性、(抽象性)
3、其他关键字:this、super、static、final、abstract、interface、package、import等
面向过程与面向过程的区别
面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。
面向对象,强调具备了功能的对象,以类和对象为最小的单位,考虑谁来做。
比如把大象放冰箱这件事:
面向过程是:把冰箱门打开;把大象放进去;关上冰箱门
面向对象是:设计类
人{
打开(冰箱){
冰箱.开门();
}
抬起(大象){
大象.抬起();
}
关闭(冰箱) {
冰箱.闭合();
}
}
冰箱{
开门(){}
闭合(){}
}
大象{
进入(冰箱){
}
}
面向对象三大特征
封装:是面向对象的特征之一,是对象和类概念的主要特性。就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
继承:面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
多态:同一个行为具有多个不同表现形式或形态的能力。是指一个类实例(对象)的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。
面向对象的两个要素:类和对象
类:对一类事物的描述,是抽象的、概念上的定义
对象:是实际存在的该类事物的每个个体,因而也被称为实例
总结:可以理解为:类 = 抽象概念的人;对象 = 实实在在的某个人。
面向对象程序设计的重点是类的设计;类的设计就是类的成员的设计。
属性和方法
常见的类的成员:属性、行为
属性 = 成员变量 = field = 域、字段
方法 = 成员方法 = 函数
类和对象的创建
package com.object;
//创建类的对象 = 类的实例化类 = 实例化类
//测试类
//类和对象的使用:
//1、创建类;2、创建类的对象;3、通过“对象.属性”和”对象.方法“调用对象的结构
public class PersonTest {
public static void main(String[] args) {
//2、创建Person类的对象,类的实例化
Person p1 = new Person();
//3(1)调用对象的结构:属性、方法
//调用属性:“对象.属性”
p1.name = "Tom";
p1.isMale = true;
System.out.println(p1.name);
//3(2)调用方法:”对象.方法“
p1.eat();
p1.sleep();
p1.talk("Chinese");
}
}
//1、创建一个Person类
class Person{
//属性
String name;
int age = 1;
boolean isMale;
//方法
public void eat(){
System.out.println("人可以吃饭");
}
public void sleep(){
System.out.println("人可以睡觉");
}
public void talk(String language){//括号里面可以加上参数
System.out.println("人可以说话,使用的是" + language);
}
}
如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)
意味着,如果我们修改一个对象的属性a,则不影响另一个对象属性a的值
Person p2 = new Person();
System.out.println(p2.name);//结果是null
System.out.println(p2.isMale);//结果是false,属性有默认初始化值
//将对象保存的对象地址值赋给了p3,导致p1和p3指向了堆空间中的同一个对象实体
Person p3 = p1;
System.out.println(p3.name);//Tom
p3.age = 10;
System.out.println(p1.age);//10
对象的内存解析
(1)内存常见的三个存放位置(注意红体字)
(2)由上述Person类进行分析
栈的特点:先进后出;new的结构都存在堆里;
Person p1 = new Person();这里的赋值操作,赋进来的是地址值;方法中的变量都是局部变量,存在栈中,栈空间中的p1指向了堆空间中的地址值;属性存在于堆空间中,这些属性会有默认初始化值,最后赋值操作改变了默认初始化值。p3只能说是新声明的变量,不能算是新创建的一个对象,所以p1和p3都指向了同一个地址值。
属性与局部变量的对比
属性(成员变量) vs 局部变量
1、相同点:
定义变量的格式相同;
都应该先声明,后使用;
变量都有其对应的作用域
2、不同点:
(1)在类中声明的位置不同——属性(成员变量):直接定义在类的一对{}中;
局部变量,声明在方法内、方法形参、代码块内、构造形参、构造器内部的变量
(2)关于权限修饰符的不同
属性:可以在声明属性时,指明其权限,使用权限修饰符。
常用的权限修饰符:private、public、protected、缺省(一种默认的权限,即没写权限),等到封装性再讲
目前声明属性,都使用缺省就行
局部变量不可以使用权限修饰符! ! !
(3)默认初始化值的情况:
属性:类的属性,根据其类型,都有默认的初始化值
整型(byte、short、int、long) 0
浮点型(float、double) 0.0
字符型(char) 0 或者'\u0000'
布尔型(boolean) false
引用数据类型(类、数组、接口) null
局部变量没有默认初始化值,意味着我们在调用局部变量之前一定要显式赋值("烙饼"一定要写出来,赋值)
特别的,形参在调用时赋值即可,如language
(4)属性——加载到堆空间中(非staticde)
局部变量——加载到栈空间
package com.object;
//类中属性(成员变量)的使用
public class UserTest {
public static void main(String[] args) {
User u1 = new User();
System.out.println(u1.name);
System.out.println(u1.age);
System.out.println(u1.isMale);
u1.talk("日语");
}
}
class User{
String name;
int age;
boolean isMale;
public void talk(String language){//language是形参,也是局部变量
System.out.println("我们使用" + language + "进行交流");
}
public void eat(){
String food = "烙饼";//局部变量,写在方法块中
System.out.println("北方人喜欢吃:" + food);
}
}
}
方法举例与声明的格式
A.方法:描述类应该具有的功能。 Math类:sqrt()\random()\... Scanner类,nextXxx()... Arrays类:sort()\binarySearch()\toString()\equals()\... B.举例: 方法:分成没有形参的和有形参的或者分成有返回值的和没有返回值的 public void eat() public void sleep(int hour) public String getName() public String getNation(String nation) C.方法的声明:(必备的几部分) 权限修饰符 返回值类型 方法名(形参列表){ 方法体 } 注意:static、final、abstract来修饰的方法,后面再讲 (1)权限修饰符:Java规定的权限修饰符有private、public、protected、缺省 目前默认是public。 (2)返回值类型:有返回值 vs 无返回值 如果方法有返回值,则必须在方法声明时指定返回值的类型,同时方法中需要使用return关键字 来返回指定类型的变量或者常量——“return 数据” 如果没有返回值,方法声明时用void来返回,如果void类型中加入了return ,则这里的return 表示的是结束此方法的意思 (3)定义的时候,该不该有返回值——看题目要求;凭经验。 (4)方法名,要有见明知意的作用 (5)形参列表:方法可以声明0个以上的形参; 格式:数据类型1 形参1,数据类型2 形参2,... 定义方法时要不要形参——看题目要求;凭经验。 (6)方法体:方法功能的体现
D.方法使用中的注意点
(1)可以调用当前类的属性和方法;特殊的,方法A中调用了方法A,叫递归方法
(2)方法中不允许定义另一个方法,如:
public void eyeTest(){
public void swim(){
}
}
以上是错误的!!!
return关键字的使用
1、使用范围:使用在方法体中
2、作用:结束方法;针对有返回值类型的方法,使用"return 数据"方法返回所要的数据。
3、return 关键字后面不能声明执行语句。(和break是一样的)
练习——类的使用
(1)类的创建和测试
package com.object;
//类的设计,设计一个Person1类
public class PersonText {
public static void main(String[] args) {
Person p1 = new Person();//先造个对象!!
p1.name = "Tom";
p1.age = 18;//这里都是用p1.属性/方法来赋值的
p1.sex = "1";
p1.study();
p1.showAge();
p1.addAge(2);
System.out.println(p1.name);
System.out.println(p1.age);
}
}
class Person{
String name;
int age;
int sex;//输入1代表男生;输入0代表女生
public void study(){
System.out.println("studying");
}
public void showAge(){
System.out.println("age:" + age);
}
public int addAge(int i){
age += i;
return age;
}
}
(2)利用面向对象的编程方法,设计Circle计算圆的面积
package com.object;
public class CircleText {
public static void main(String[] args) {//main方法是程序的入口
Circle c1 = new Circle();//先造对象
c1.radius = 2.1;
System.out.println(c1.findArea());
}
}
//圆
class Circle{
//属性
double radius;
//功能:求圆的面积
public double findArea(){
double area = Math.PI * radius * radius;
return area;
}
/*以上是有返回值的,下面看无返回值的*/
public void findArea(){
double area = Math.PI * radius * radius;
System.out.println(area);
//在调用这个方法的时候,直接写c1.findArea();
}
练习——方法的声明
package com.object;
//1、声明一个method方法,在方法中打印一个10*8的*型矩阵,在mian方法中调用该方法。
/*/2、修改上一个程序,在method方法中,除打印一个10*8的*型矩阵外,再计算该矩阵的面积值并打印,
并将其作为方法的返回值。在main方法中调用该方法,接收返回值的面积并打印
3、修改上一个程序,在method方法提供m和n两个参数,方法中打印一个m*n的*型矩阵,
并计算该矩阵的面积,将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
*/
public class ExerTest {
public static void main(String[] args) {
ExerTest test = new ExerTest();//要先造对象
//int text = test.method();
//System.out.println(text);
System.out.println(test.method(12, 10));
}
// public void method(){
// for(int i = 0;i < 10;i++) {
// for (int j = 0; j < 8; j++) {
// System.out.print("* ");
// }
// System.out.println();
// }
// }
/* public int method(){
for(int i = 0;i < 10;i++) {
for (int j = 0; j < 8; j++) {
System.out.print("* ");
}
System.out.println();
}
return 10 * 8;
}*/
//在method方法提供m和n两个参数,方法中打印一个m*n的*型矩阵,
并计算该矩阵的面积,将其作为方法返回值。
public int method(int m,int n){
for(int i = 0;i < m;i++) {
for (int j = 0; j < n; j++) {
System.out.print("* ");
}
System.out.println();
}
return m * n;
}
}
练习——对象数组
定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。 创建20个学生对象,
学号为1到20,年级和成绩都由随机数确定。
问题一:打印出3年级(state值为3)的学生信息。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
提示:
① 生成随机数:Math.random(),返回值类型double;
② 四舍五入取整:Math.round(double d),返回值类型long
package com.object;
public class StudentTest {
public static void main(String[] args) {
//声明Student类型的数组
Student[] stus = new Student[20];//对象数组
for(int i = 0;i < stus.length;i++){
//相当于给数组元素赋值
stus[i] = new Student();//new过了对象,就是地址值了
//给Student对象的属性赋值
stus[i].number = (i + 1);
//年级:【1,6】
stus[i].state = (int)(Math.random() * (6 - 1 + 1) + 1);
//成绩:【0,100】
stus[i].score = (int)(Math.random() * (100 - 0 + 1) + 0);
}
//遍历学生数组
for(int i = 0;i < stus.length;i++){
System.out.println(stus[i].info());
}
System.out.println("*****************");
//问题一:打印出3年级(state值为3)的学生信息。
for(int i = 0;i < stus.length;i++){
if(stus[i].state == 3){
System.out.println(stus[i].info());
}
}
System.out.println("*****************");
//问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
for(int i = 0;i < stus.length - 1;i++){
for(int j = 0; j < stus.length - 1 - i;j++){
if(stus[j].score > stus[j + 1].score){
//如果需要排序,交换的是数组的元素:Student对象!!!
Student temp = stus[j];
stus[j] = stus[j + 1];
stus[j + 1] = temp;
}
}
}
for(int i = 0;i < stus.length;i++){
System.out.println(stus[i].info());
}
}
}
//
class Student{
int number;//学号
int state;//年级
int score;//成绩
//显示学生信息的方法
public String info(){
return "学号:" + number + ",年级:" + state + ",成绩:" + score;
}
}
对象数组的内存解析
引用类型的变量,只可能存储两类值,null或者地址值(含变量的类型)
JVM内存解析与对象内存解析
对象的创建和内存解析
Person p1 = new Person();
Person p2 = new Person();//都叫做new了一个对象
Person p3 = p1;//并没有新创建一个对象的属性a,则不影响另外一个对象属性a的值。
理解万事万物皆对象
1、在Java语言范畴中,我们都将功能结构等封装到类中,通过类的实例化,来调用具体的功能结构。
》Scanner/String
》文件
》网络资源
2、涉及到Java语言与前端Html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类和对象。
匿名对象的使用
1、定义:我们创建的对象,没有显式的赋值给一个变量名,即为匿名对象。
2、特征:匿名对象只能调用一次。
自定义数组工具类
package com.object;
public class ArrayUtil {//自定义数组的工具类
//求数组的最大值
public int getMax(int[] arr) {
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (max <= arr[i]) {
max = arr[i];
}
}
return max;
}
//求数组的最小值
public int getMin(int[] arr) {
int min = arr[0];
for (int i = 0; i < arr.length; i++) {
if (min >= arr[i]) {
min = arr[i];
}
}
return min;
}
//求数组总和
public int getsum(int[] arr) {
int sum = arr[0];
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
//求数组的平均值
public int getAvg(int[] arr) {
/*int ave = 0;
int sum = 0;
for(int i = 0;i < arr.length;i++){
sum += arr[i];
}
ave = sum / (arr.length - 1);
return ave;*/
return getsum(arr) / arr.length;//方法中调方法
}
//反转数组
public void reverse(int[] arr) {
for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// for(int i = 0;i < arr.length;i++){
// System.out.println(arr[i] + '\t');
// }不用再打印出来了
}
//复制数组
public int[] copy(int[] arr) {
int[] arr1 = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
arr1[i] = arr[i];
}
return arr1;
}
//数组排序
public void sort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] <= arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
//遍历数组
public void print(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i] + '\t');
}
}
//查找指定元素
public int getIndex(int[] arr, int dest) {
//线性查找
/*boolean isFlag = true;
for (int i = 0; i < arr.length; i++) {
if (dest == arr[i]) {
System.out.println("找到了,位置是:" + i);
isFlag = false;
break;
}
}不用那么复杂,找到之后直接返回找的的索引即可,这就是有返回值得好处*/
for (int i = 0; i < arr.length; i++) {
if (dest == arr[i]) {
return i;
}
}
return -1;//表示循环走完了,还没有找到。
}
}
//二分查找一定要是有序的,这里不一定能用
/*int start = 0;
int end = arr.length - 1;
int middle = (start + end) / 2;
boolean isFlag = true;
for(int i = start;i <= end;i++){
if(dest == arr[middle]){//注意,这里是拿arr[middle]来比,不是middle
// dest = middle;
System.out.println("找到了,位置是:" + middle);
isFlag = false;
break;
}
if(dest < arr[middle]){
end = middle - 1;
}
if(dest > arr[middle]){
start = middle + 1;
}
}
if(isFlag){
System.out.println("很遗憾没有找到");
}
return 0;
}*/
方法的重载
重载的细节:
(1)“两同一不同”:同一个类、相同方法名
参数列表不同,参数个数不同,参数类型不同
(2)判断是否是重载,跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!
(3)在通过对象调用方法时,如何确定某一个指定方法:
方法名----->参数列表
判断方法的重载,关于概念的例题:
可变个数形参的方法
(1)可变个数形参的格式,数据类型...变量名
例如:String ... strs
(2)当调用可变个数形参的方法时,传入的参数(必须和参数类型相同)个数可以是:0个、1个、2个或多个。
(3)可变个数形参的方法与本类中的方法名相同,形参不同的方法之间构成重载,例如:
public void show(String s){ System.out.println("show(String)"); } public void show(String ... strs){ System.out.println("show(String ... strs)"); }
(4)可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。话句话说,二者不能共存。
例如:
public void show(String ... strs){ System.out.println("show(String ... strs)"); } public void show(String[] strs){ System.out.println("show(String ... strs)"); }
(5)可变个数形参在方法的形参中,必须声明在末尾
public void show(String ... strs,int i)这种写法是错误的;
public void show(int i,String ... strs)才是对的。
(6)可变个数形参在方法的形参当中,最多只能声明一个可变形参。
方法参数的值传递机制(难点)
如果变量是基本数据类型,此时赋值的是变量所保存的数据值;
如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。
package com.object;
import java.util.Date;
/*
方法形参的传递机制、值传递
1.形参:方法定义时,声明的小括号里的参数
实参:方法调用时,实际传递给形参的值的数据
2.值传递机制:
*/
public class ValueTransferTest {
public static void main(String[] args) {
//交换两个变量的值的操作
System.out.println("**********基本数据类型**********");
int m = 10;
int n = m;
System.out.println("m = " + m + ",n = " + n);
n = 20;
System.out.println("m = " + m + ",n = " + n);
System.out.println("*********引用数据类型*******");
Order o1 = new Order();
o1.orderId = 1001;
Order o2 = o1;//赋值以后,o1和o2的地址值相同,都指向了堆空间中同一个地址值
System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " + o2.orderId);
o2.orderId = 1002;
System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " + o2.orderId);
//o1、o2的值都变成了1002
}
}
class Order{
int orderId;
}
值传递机制:
如果参数是基本数据类型,此时实参给形参的是实参真实存储的数据值;
(1)此时实参给形参的是实参真实存储的数据值,即10和20
package com.object;
public class ValueTransferTest {
public static void main(String[] args) {
//交换两个变量的值的操作
System.out.println("**********基本数据类型**********");
int m = 10;
int n = 20;
System.out.println("m = " + m + ",n = " + n);
//调方法需要用到所在类的对象
ValueTransferTest test = new ValueTransferTest();
test.swap(m,n);
System.out.println("m = " + m + ",n = " + n);//没换成
}
public void swap(int m,int n){
int temp = m;
m = n;
n = temp;
}
}
运行结果:(没有换成)
如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值
package com.Object1;
public class ValueTransferTest1 {
public static void main(String[] args) {
Data data = new Data();
data.m = 10;
data.n = 20;
System.out.println("m = " + data.m + ",n = " + data.n);
ValueTransferTest1 test = new ValueTransferTest1();
test.swap(data);
System.out.println("m = " + data.m + ",n = " + data.n);
}
public void swap(Data data) {
int temp = data.m;
data.m = data.n;
data.n = temp;
}
}
class Data{
int m;
int n;
}
面向对象特征之一:封装与隐藏
隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,把该暴露的暴露出来,就是封装性的设计思想。
(1)问题的引入:
当我们创建一个类的对象之后,我们可以通过“对象.属性”的方式,对对象的属性进行赋值。这里的赋值操作要受到属性的数据类型和存储范围制约,除此之外,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过这个方法进行限制条件的添加。同时,我们需要避免用户在使用“对象.属性”的方式对属性进行赋值,则需要将属性声明为私有的(private)
——>此时,针对于属性就体现了封装性。
(2)封装性的体现:
a.我们将类的属性私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值。(之一)
b.不对外暴露的私有的方法;单例模式(以后讲)
package com.base;
public class AnimalTest {
public static void main(String[] args) {
Animal a = new Animal();
a.name = "大象";
a.age = 4;
a.show();
a.setLegs(-6);
a.show();
}
}
class Animal{
String name;
int age;
private int legs;//给变量加上限制private,相当于没有直接对外暴露。
//问题:怎么给legs加上限制——提供方法
//对属性的设置
public void setLegs(int l){
if(l >= 0 && l % 2 == 0){
legs = l;
}else{
legs = 0;
}
}
//对属性的获取
public int getLegs(){
return legs;
}
public void eat(){
System.out.println("动物进食");
}
public void show(){
System.out.println("name = " + name + ",age = " + age + ",legs = " + legs);
}
}
四种权限的修饰的理解
封装性的体现需要权限修饰符来配合。
1、Java规定的4种权限(从小到大排列):private、缺省、protected、public
2、这四种权限可以用来修饰类及类的内部结构、属性、方法、构造器、内部类。
3、具体的,四种权限都可以修饰类的内部结构,属性、方法、构造器、内部类。修饰类的话,只能使用:缺省、public。
封装性的基本使用
1、创建程序,在其中定义两个类:Person和PersonTest类。定义如下:用setAge()设置人的合法年龄(0-130),用getAge()返回人的年龄。在Person类中实例化Person类的对象b,调用setAge()和getAge()方法,体会Java的封装性。
构造器的基本理解
A.类的结构之三,构造器;构造器的作用:
(1)创建对象,对对象进行初始化
Person p1 = new Person();//这个Person()就是构造器
(2)如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
定义构造器的格式:权限修饰符 类名(形参列表)
构造器和方法的区别(首先就是格式不同)
/构造器 public Person(){ System.out.println("Person()..."); } //方法 public void eat(){ System.out.println("人吃饭"); }
B.构造器使用的细节说明
(1)一个类中定义的多个构造器,彼此构成重载。
(2)一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器。
(3)一个类中,至少有一个构造器。
总结:属性赋值的先后顺序
(1)默认初始化
(2)显式初始化
(3)构造器中赋值
(4)通过“对象.方法”或“对象.属性”赋值
以上操作的先后顺序:1-2-3-4
JavaBean
是一种java语言写成的可重用组件,是指符合以下标准的Java类:
(1)类是公共的
(2)有一个无参的公共的构造器
(3)有属性,且有对应的get、set方法。
用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以用Java代码创建的对象进行打包,并且其他的开发者可以通过内部的JSP页面、Servlet、其他JavaBean、apple程序或者应用来使用这些对象。用户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
this的使用
this可以用来修饰:属性、方法、构造器
this修饰属性和方法:
this 可以理解为:当前对象
在类的方法当中,我们可以使用“this.属性”或“this.方法”的方式,调用当前对象属性或方法。但是,在通常情况下,我们都选择省略“this.”。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用“this.变量”的方式,表明此变量是属性,而非形参。
其实就是重名的时候加上"this."进行区分。
this调用构造器
(1)我们在类的构造器中,可以显式的使用“this(形参列表)”方式,调用本类中的其他构造器
(2)构造器中不能通过“this(形参列表)”调用自己。
(3)如果一个类中有n个构造器,则最多有n - 1个构造器中使用了“this(形参列表)”。
(4)规定:“this(形参列表)”必须声明在当前构造器的首行。
(5)构造器内部,最多只能声明一个“this(形参列表)”,用来调用其他的构造器。
对象之间如何比大小——比属性,关于对象排序,都是按照属性来排。