黑马程序员_毕向东JAVA基础_面向对象(封装&继承&多态)

时间:2021-09-04 12:11:24

---------------------- ASP.Net+Android+IO开发S.Net培训、期待与您交流! ----------------------

   面向对象

万物皆对象。

面向对象是相对面向过程而言:面向对象和面向过程都是一种思想。面向过程强调的是功能行为;面向对象是将功能封装进对象,强调具备了功能的对象。

面向对象是基于面向过程的。


面向对象的特征:封装,继承,多态。

以后开发:其实就是找对象使用,没有对象,就创建对象。

找对象:建立对象,使用对象,维护对象的关系。

举例:

现实中的对象:张三,李四。

想要描述:提取对象中的共性内容,对具体进行抽象。

共性内容:姓名、年龄、性别等。


类和对象的关系:

类:对显示生活中的事物的描述。

对象:就是这类事物,实实在在的个体。


成员变量和局部变量:

作用域:成员变量作用于整个类中,局部变量作用于函数中或语句中。

在内存中的位置:成员变量在堆内存中,局部变量在栈内存中。

生命周期:成员变量随着类的创建而创建,存在堆内存中,随着类的消失而消失。

   局部变量随着方法调用或者语句执行而存放在栈内存中,调用结束后或语句结束后自动释放。

class Person
{
private String name; // 成员变量

public void study()
{
int a = 1;//局部变量
}
}

匿名对象:

匿名对象是对象的简化形式。

匿名对象两种使用情况:

<1>当对对象方法仅进行一次调用的时候。可以用匿名对象来完成,这样写比较简化。

如果对一个对象进行多个成员调用,必须给这个对象起个名字。

<2>匿名对象可以作为实际参数进行传递。

举例匿名对象的实现:new Car().num = 5;

show(new Car());

                                 黑马程序员_毕向东JAVA基础_面向对象(封装&继承&多态)

封装(Encapsulation)


封装:是指隐藏对象的属性和实现细节,仅对外提供公共的访问方式。

好处是:将变化隔离,便于使用,提高重用性,提高安全性。

封装的原则:将不需要对外提供的内容都隐藏起来。

把属性都隐藏,提供公共方法对其访问。


private:私有,权限修饰符。用于修饰类中的成员(成员变量,成员函数),私有只有在本类中有效。将成员变量私有化后,类以外即使建立了对象也不能直接访问。要想访问,需要在Person类中提供对应访问age的访问方式。之所以对外提供访问方式,就因为可以在访问方式中加入逻辑判断语句。对访问数据进行操作,提高代码的健壮性。

封装不是私有,私有仅仅是封装的一种表现形式。

黑马程序员_毕向东JAVA基础_面向对象(封装&继承&多态)                          

构造函数

特点:

1.函数名与类名相同。

2.不用定义返回值类型。

3.不可以写return语句。

作用:给对象初始化。

注意:

1.默认构造函数的特点。

2.多个构造函数是以重载的形式存在的。

对象一建立就会调用与之对应的构造函数,当类中没有定义构造函数时,那么系统会默认给该类加入一个空参数的构造函数(方便初始化)。当在类中定义构造函数时,默认的构造函数就消失了。

构造函数和一般函数在写法上有不同,在运行上也有不同。构造函数在对象一建立就运行,给对象初始化。而一般函数是在对象调用才执行,是给对象添加对象具备的功能。一个对象建立,构造函数只能运行一次,而一般函数可以被调用多次。


什么时候定义构造函数呢?

当分析事物,该事物具备一些特征或行为,那么将这些内容定义在构造函数中。


构造代码块:

作用:给对象初始化。对象一建立就运行,而且优先于构造函数执行。

和构造函数的区别是:构造代码块是给所有对象进行统一初始化,而构造函数是给对应的对象初始化。

构造代码块中定义的是不同对象共性的初始化对象。


This:

看上去是用于区*部变量和成员变量重名的问题。

This为什么能解决这个问题?代表什么呢?

this代表它所在函数所属对象的引用。简单说,哪个对象在调用this所在的函数,this就代表那个对象。

this的应用:当定义类中的功能,该函数内部要用到调用该函数的对象时,这时用this来表示这个对象。

本类功能内部使用到本类对象,都用this表示。

this语句:用于构造函数之间进行互相调用;

 this(name)只能定义在构造函数的第一行。因为初始化要先运行。

class Person
{
private String name; // 成员变量
private int age;

Person(String name)
{
this.name = name;
}

Person(String name,int age)
{
//this.name = name;
this(name);//调用构造函数。
this.age = age;
}

static(静态)关键字

static 关键字:用于修饰成员(成员变量和成员函数)

被修饰后的成员具备以下特点:

<1>随着类的加载而加载;也就是说静态会随着类的消失而消失,它的生命周期最长。

<2>优先于对象存在;静态先存在,然后再是对象。

<3>被所有对象所共享;

<4>可以直接被类名调用。

使用注意:

<1>静态方法只能访问静态成员。

<2>静态方法不可以写this,super关键字。

<3>主函数是静态的。


static用于修饰成员,不需要每个成员都存储。

当成员被静态修饰后,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调用。类名.成员对象。

方法区(共享区,数据区):用于存储类中的方法,共享数据。

实例变量和类变量的区别:

1.存放位置:类变量随着类的加载而存在于方法区中。实例变量随着对象的建立而存在于堆内存中。

2.生命周期:类变量生命周期最长,随着类的消失而消失。实例变量生命周期随着对象的消失而消失。

3.主函数是静态的。


静态使用的注意事项:

1.静态方法只能访问静态成员,非静态方法既可以访问静态也可以访问非静态。

2.静态方法中不可以定义this,super关键字。因为静态优先于对象存在,所以静态方法中不可以出现this。


静态有利有弊:

利:对对象共享数据进行单独空间的存储,节省空间。没有必要每个对象中都存储一份。可以直接被类名调用。

弊:生命周期过长,访问会出现局限性(静态虽好,只能访问静态)


主函数:是一个特殊函数,作为程序的入口,可以被JVM调用。

主函数定义:

public:代表该函数的访问权限最大。

static:代表主函数随着类的加载就已经存在了。

void:主函数没有具体的返回值。

main:不是关键字,但是一个特殊的单词,可以被JVM识别。

(String[] args):函数的参数,参数类型是一个数组,该数组中的元素是字符串,字符串类型的数组。

主函数是固定格式的:JVM识别。唯一可以改变的是args。Arguments参数。

JVM调用主函数时,传入的是new String[0];


什么时候使用静态?要从两个方面下手,因为静态修饰内容有成员变量和成员函数。

什么时候定义静态的变量呢?

当对象中出现共享数据时,该数据被静态所修饰,对象中特有数据要定义成非静态存在于堆内存中。

什么时候定义静态的函数呢?

当功能内部没有访问到非静态数据(对象的特有数据),那么该功能可以定义成静态的。


        代码:

class Person
{
String name;//成员变量,实例变量,需要对象存在
static String country = "CN";//类变量,类存在就存在
/*Person()
{

}
Person(String name)
{
this.name = name;
}*/
public void show()
{
System.out.println("name="+name+",country="+country);
}
}
class StaticDemo
{
public static void main(String[] args)
{
Person p = new Person();
p.name = "zhangsan";
p.show();

//System.out.println(p.country);
}
}

静态的应用:每一个应用程序中都有共性的功能,可以将这些功能进行抽取,独立封装。以便复用。


/*
定义一个数组的工具类,包括的功能:求最大者,最小值,选择排序,冒泡排序,折半查找。
*/


class ArrayTool
{
/*私有化构造函数,防止定义无效的对象*/
private ArrayTool()
{
}
/*求最大值的函数*/
public static int getMax(int[] arr)
{
int max = arr[0];
for ( int i = 1; i < arr.length ;i++ )
{
if(arr[i]> max)
max = arr[i] ;
}
return max;
}
/*求最小值*/
public static int getMin(int[] arr)
{
int min = arr[0];
for ( int i = 1; i < arr.length ;i++ )
{
if(arr[i]< min)
min = arr[i] ;
}
return min;
}
/*选择排序*/
public static void selectSort(int[] arr)
{
for (int x = 0; x < arr.length-1 ; x++)
{
for (int y = x + 1; y < arr.length ; y++ )
{
if(arr[x] > arr[y])
swap(arr,x,y);
}
}
}

/*冒泡排序*/
public static void bubbleSort(int[] arr)
{
for (int x = 0; x <arr.length -1 ; x++ )
{
for (int y = 0;y <arr.length-x-1 ;y++ )
{
if (arr[y+1] < arr[y])
swap(arr,y,y+1);


}
}

}
/*交换函数,只给排序用,也只作用于本类中,可以私有它*/
private static void swap(int[] arr,int a,int b)
{
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp ;
}
/*折半查找*/
public static int halfSearch(int[] arr,int num)
{
int min = 0 ;
int max = arr.length -1;
int mid = (min+max)/2;
while (min < max)
{
if(arr[mid] < num)
min = mid ;
else if (arr[mid] > num)
max = mid ;
else
return mid;

}
return -1;//数组中找不到这个数
}
/*写一个打印函数*/
public static void printArray(int[] arr)
{
System.out.print("[");
for (int i = 0; i < arr.length ; i++ )
{
System.out.print(arr[i]+",");

}
System.out.println("]");
}
}
class  ArrayToolDemo{public static void main(String[] args) {int[] arr = new int[]{1,2,5,8,3,4,8,9};//int index = ArrayTool.halfSearch(arr,8);System.out.println("index="+index);ArrayTool.printArray(arr);ArrayTool.selectSort(arr);ArrayTool.printArray(arr);ArrayTool.bubbleSort(arr);ArrayTool.printArray(arr);System.out.println("min="+ArrayTool.getMin(arr));System.out.println("max="+ArrayTool.getMax(arr));}}

我们发现:虽然可以通过建立ArrayTool的对象使用这些工具方法对数组进行操作。但问题是:

1.对象是用于封装数据的。可是ArrayTool对象并未封装特有数据。

2.操作数组的每一个方法都没有用到ArrayTool对象中的特有数据。

这是我们考虑,让程序更严谨,要不需要对象的。

可以将ArrayTool中的方法都定义成static的,直接通过类名调用即可。

将方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象的。为了严谨,强制该类不能建立对象。

可以通过将构造函数私有化完成。


一个类中默认会有一个空参数的构造函数,这个默认的构造函数的权限和所属类一致。

如果类被public修饰,那么默认的构造函数也带public修饰符。如果类没有被public修饰,那么默认的构造函数,也没有被public修饰。

默认构造函数的权限是随着类的变化而变化的。


静态代码块

格式:

static

{

静态代码块中的执行语句;

}

特点:随着类的加载而执行,只执行一次。用于给类初始化。并优先于主函数。

class StaticCode
{
private int age = 1;// 显示初始化
StaticCode()
{
System.out.println('b');//无对象的构造函数
}
static
{
System.out.println('a');//静态代码块
}
{
System.out.println(age);//构造代码块
}
StaticCode(int age)
{
this.age = age;
System.out.println('d');//有构造函数给对应对象初始化
System.out.println(age);
}
public static void show()
{
System.out.println("show");
}
}
class StaticCodeDemo
{
/*static
{
System.out.println('b');
}*/

public static void main(String[] args)
{
//new StaticCode();//匿名对象?
//new StaticCode();
//StaticCode.show();
//StaticCode s = null;// 不加载类。
new StaticCode(1);

System.out.println("Hello World!");
}
/*static
{
System.out.println('c');
}*/

}

优先级: 静态代码块初始化>默认初始化>显示初始化>构造代码块初始化>构造函数初始化

运行机制:

<1> 因为new用到了Person.class,所以会找到Peron.class文件并加载到内存中。

<2>执行该类中的static代码块,如果有的话,该Person.class类进行初始化。

<3>在堆内存中开辟空间,分配内存地址。

<4>在堆内存中建立对象的特有属性。并进行默认初始化。

<5>对属性进行显示初始化。

<6>对对象进行构造代码块初始化。

<7>对对象进行对应的构造函数初始化。

<8>将内存地址赋给占内存的p变量。

黑马程序员_毕向东JAVA基础_面向对象(封装&继承&多态)


非静态(省略this点)方法调用过程:(p.setName的调用)

1.      在栈内存中开辟setName,里边存this(指向将要调用这个函数的对象)和 name;

2.      This 指向P,所以将p指向的地址就给了this。

3.      This就指向了堆内存中的对象。

4.      Name就指向了内存中的name,并对他进行了修改。

 

静态(省略类名点)(showCountry),用类名调用,与堆内存无关。

黑马程序员_毕向东JAVA基础_面向对象(封装&继承&多态)


继承

将类中的共性提取出来,单独封装,搞个父类用于继承。

继承:1.提高代码的复用性;2,.继承让类与类直接产生了关系,有了这个关系才有了多态的特征。

注意:千万不要为了获取其他类的功能,简化代码而继承。必须是类与类直接有所属关系才可以继承。所属关系:is a。

java语言中:java只支持单继承,不支持多继承。

因为多继承容易带来安全隐患,当多个父类定义了相同功能,而功能内容不容时,子类对象不确定要运行哪一个。

但是java保留了这种机制,并用另一种体现形式来表示:多实现。


java支持多层继承。也就是一个继承体系。

如何使用一个继承体系中的功能呢?想要使用体系,先查阅体系中的父类的描述,因为父类中定义的是该体系中的共性功能。通过了解共性功能,就可以知道该体系的基本功能。通过了解共性功能,就可以知道该体系的基本功能。那么这个体系已经基本可以使用了。那么在具体调用时,要创建最子类的对象,为什么呢?

1.是因为有可能父类不可能创建对象。

2.是创建子类对象可以使用更多的功能,包括基本的,也包括特有的。

简单一句话:查阅父类功能,创建子类对象,使用功能。


如果父类和子类有相同的变量,打印的是子类的。

/* 子父类出现后,类成员特点

*/

class Fu
{
int num = 4;

}


class Zi extends Fu //zi类继承父类
{
int num = 5;
}

class ExtendsDemo2
{
public static void main(String[] args)
{
Zi z = new Zi();
System.out.println(z.num+"....."+z.num);
}
}

打印结果:5.....5


this代表本类对象的引用,super代表父类对象的引用。

子父类变量特点:如果子类中出现非私有的同名成员变量时,子类要访问本类中的变量,用this。

子类要访问父类中的同名变量时,用super。

super的使用和this几乎一致。this代表本类对象的引用,super代表父类对象的引用。

类中的成员包括:变量,函数,构造函数。


子父类中函数的特点:

当子类中出现和父类一模一样的函数时,当子类对象调用该函数,会运行子类函数的内容。如同父类的函数被覆盖一样。这种情况是函数的另一个特性:重写(覆盖)。

当子类继承父类,沿袭了父类的功能到子类中,但子类虽有该功能,但是功能内容却和父类不一致,这时没有必要定义新功能,而是使用覆盖特性,保留父类的功能定义,

并重写父类。可用于扩展。

子类覆盖父类,必须保证子类权限大于等于父类权限,才能覆盖,否则编译失败。

静态只能覆盖静态。

注意:

重载:只看同名函数的参数列表。

重写:子父类方法要一模一样。

class Fu
{
Fu()
{
System.out.println("Fu");
}

}
class Zi extends Fu
{
Zi()
{
//super();
System.out.println("zi");

}
}



class ExtendsDemo3
{
public static void main(String[] args)
{
Zi z = new Zi();
System.out.println("Hello World!");
}
}

程序会打印:Fu zi。

在对子类对象进行初始化时,父类的构造函数也会运行,那是因为子类的构造函数默认第一行有一条隐式语句super();

super():会访问父类中空参数的构造函数,而且子类中所有的构造函数默认第一行都是super()。

为什么子类一定要访问父类中的构造函数呢?

因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类中如何对数据进行初始化的。所以子类对象初始化时,需要先访问父类中的构造函数。如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。

super()语句一定定义在子类构造函数的第一行。

<构造函数中this()与super()>只能有一个。子类中至少有一个构造函数访问父类。

子类的实例化过程。

结论:子类的所有的构造函数,默认都会访问父类中空参数的构造函数,因为子类每一个构造函数内的第一行都有一句隐式super();当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中的构造函数。

当然:子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。

子类中至少会有一个构造函数会访问父类中的构造函数。Object(所有类的父类)


final关键字

final:最终。作为一个修饰符。

<1>final可以修饰类,方法,变量。

<2>final修饰的类不可以被继承。

<3>final修饰的方法不可以被覆盖。

<4>final修饰的变量是一个常量。只能被赋值一次。

<5>内部类只能访问被final修饰的局部变量。

当在描述事物时,有些数据的出现值是固定的,那么这是为了增强阅读性,都给这些值起个名字。而这个值不需要改变,所以加上final修饰。作为常量:常量的书写规范所有字母都大写,如果由多个单词组成,单词间通过”_”连接。

目前为止,类有三个修饰符  public final  什么都不写。


抽象类:

当多个类中出现相同的功能,但功能主体不同,这时可以进行向上抽取。这时,只抽取功能定义,不抽取功能主体。

抽象类的特点:

1.抽象方法一定在抽象类中;

2.抽象方法和抽象类都必须被abstract关键字修饰;

3.抽象类不可以用new创建对象,因为调用抽象方法没意义。

4.抽象类中的方法要被使用,必须由子类复写所有的抽象方法后,建立子类对象调用。

如果子类只覆盖部分抽象方法,那么该子类还是一个抽象类。

抽象类和一般类没有太大的不同:该如何描述事物,就如何描述事物,只不过,该事物出现了一些看不懂的东西。这些不确定的部分,也是给事物的功能,需要明确出现,

但是无法定义主体,通过抽象方法来表示。抽象类比一般类多了个抽象函数。抽象类不可以实例化。

特殊:抽象类中可以不定义抽象方法,这样做仅仅不让该类建立对象。

abstract class Employee//定义一个抽象类
{
/*提取出姓名,ID,工资是员工和经理共有的,可以被继承*/
private String name ;
private String id;
private double pay;
Employee(String name,String id ,double pay)
{
this.name = name;
this.id = id;
this.pay = pay;
}
public abstract void work(); //工作方式,经理和员工不同,定义一个抽象方法


}

class Manager extends Employee
{
private int honus;
Manager(String name,String id ,double pay,int honus)
{
super(name,id,pay);//向上指向父类
this.honus = honus;//指向本类中的奖金
}
public void work()
{
System.out.println("Manager");
}

}

class Worker extends Employee
{
Worker(String name,String id ,double pay)
{
super(name,id,pay);

}
public void work()
{
System.out.println("worker");
}

}
class Compay
{
public static void main(String[] args)
{
Worker w = new Worker("lisi","1",2222);
w.work();

System.out.println("Hello World!");
}
}

获取一段程序运行的时间原理:获取程序开始和结束的时间并相减

获取时间: System。CurrentTimeMillis()

模板方法:

在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定的部分,那么这时就将不确定的部分暴露出去。由该类的子类去完成。

abstract class getTime
{
public final void getTime() //无法重写
{
long start = System.currentTimeMillis();
run();
long end = System.currentTimeMillis();
System.out.println("毫秒:"+(end - start));

}
abstract public void run();//抽象方法供子类调用
}

class DmRun extends getTime
{
public void run()
{
for (int i = 0;i < 10000 ;i++ )
{
System.out.print(i);
}
}

}


class Get
{
public static void main(String[] args)
{
DmRun d = new DmRun();
d.getTime();
System.out.println("Hello World!");
}
}

接口

接口的出现将”多继承“通过”多实现“来实现。

接口中的成员修饰符是固定的。

成员变量:public static final

成员函数:public abstract

接口:初期理解,可以认为是一个特殊的抽象类。当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。

接口中的成员都是public的。

接口:是不可以创建对象的,因为有抽象方法。需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化。否则子类是一个抽象类。

interface  Inter
{
public static final int num = 3;
public abstract void show();

}
class Test1
{
public void show()
{
System.out.println("父类");
}
}

class Test2 extends Test1 implements Inter
{
/*
public void show()
{
System.out.println("子类");
}*/

}
class InterDemo
{
public static void main(String[] args)
{
Test2 t = new Test2();
t.show();
System.out.println(t.num);
}
}

接口可以实现多实现。因为没有方法主体,可以由子类任意实现。

一个类只能继承一个类,同时也可以连接好几个接口

类与类之间是继承关系,类和接口是实现关系,接口和接口之间是继承关系。

接口的特点:

1.接口是对外暴露的规则。

2.接口是程序的功能扩展。

3.接口可以用来多实现。

4.类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。

5.接口与接口之间可以有继承关系。

基本功能定义在类中,扩展功能在接口中。

interface Inner
{
void method();
}

class Test
{

/*补足代码,通过匿名内部类,
我先用内部类写,然后再简化*/

class Inners implements Inner
{
void method()
{
System.out.println("Inners");
}
}
public void function()
{
new Inners().method();
}
}

class InnerClassTest
{
public static void main(String[] args)
{
//Test.function().method();
Test.function();
System.out.println("Hello World!");
}
}

多态

定义:某一类事物的多种存在形态。

多态的表现:父类的引用指向了自己的子类对象。父类的引用也可以接受自己的子类对象。

多态的前提:必须是类与类之间有关系,要么继承,要么实现。通常还有一个前提:存在覆盖。

多态的好处:多态的出现大大的提高了程序的扩展性。

多态的弊端:提高了扩展性,但是只能使用父类中的引用访问父类中的成员。

多态的应用:

黑马程序员_毕向东JAVA基础_面向对象(封装&继承&多态)

我们能转换的是父类应用指向了自己的子类对象时,该应用可以被提升,也可以被转换。多态自始至终都是子类对象在变化。

Instanceof :判断某一类型的引用指向什么类型。


在多态中的成员函数的特点:

在编译时期:参阅引用型变量所属的类中是否有调用方法。如果有,编译通过,如果没有,编译失败。

在运行时期:参阅对象所属的类中是否有调用方法。

简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。

在多态中,成员变量的特点:无论编译和运行,都参考左边(引用型变量所属的类)。

在多态中,静态成员函数的特点,无论编译和运行,都参考左边。

PCI:黑马程序员_毕向东JAVA基础_面向对象(封装&继承&多态)

interface PCI
{
public void open();
public void close();
}


class MainBoard
{
public void run()
{
System.out.println("manboard run");
}
public void usePCI(PCI p)//接口型引用指向自己的子类对象(属于多态)PCI p = new NetCard();
{
if(p!=null)
{
p.open();
p.close();
}

}
}
class NetCard implements PCI
{
public void open()
{
System.out.println("NetCard open");
}
public void close()
{
System.out.println("NetCard close");
}
}
class SoundMusic implements PCI
{
public void open()
{
System.out.println("Music open");
}
public void close()
{
System.out.println("Music close");
}
}



/*class MainBoard
{

public void run()
{
System.out.println("mainboard run");
}
public void useNetCard(NetCard c)
{
c.open();
c.close();

}
}

class NetCard
{
public void open()
{
System.out.println("NetCard open");
}
public void close()
{
System.out.println("NetCard close");
}
}*/


class DuoTaiDemo7
{
public static void main(String[] args)
{
MainBoard mb = new MainBoard();
mb.run();
//mb.useNetCard(new NetCard());
mb.usePCI(null);
mb.usePCI(new NetCard());
mb.usePCI(new SoundMusic());
}
}

Object:超类,该类中定义的肯定是所有对象都具备的功能。

equals方法比较的哈希值。

object类中已经提供了对对象是否相同的比较方法,如果自定义类中也有比较相同的功能,没有必要重新定义。只要沿袭父类中的功能,建立自己特有的比较内容即可。这就是覆盖。

class Test //extends Object
{
private int num;
Test(int num)//定义Test构造函数,用于初始化
{
this.num = num;
}
public boolean equals(Test obj)//1.object obj = new test();多态2.重写了父类中的equals函数,为什么要重写呢,因为父类中的只能比较对象指向的地址。
{
if(!(obj instanceof Test))
return false;
Test t = (Test)obj;//将obj转回Test类型
return this.num ==t.num;//将调用这个函数的对象的num与要比较的对象的num进行比较。
}
}
class Demo1
{
public static void main(String[] args)
{
/*Test a = new Test();
Test b = new Test();

System.out.println(a.equals(b));*/// 由于对象a和对象b指向的不是相同的地址,所以输出false、
Test a = new Test(1);
Test b = new Test(1);

System.out.println(a.equals(b)); //比较两个对象成员的数值()
}
}

内部类

1.内部类可以直接访问外部类中的成员,包括私有成员。之所以内部类可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用。

格式: 外部类名.this

2.外部类要访问内部类中的成员必须建立内部类的对象。

访问格式:

1.当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,可以直接建立内部类对象。

格式:外部类名.内部类名. 变量名 = 外部类对象.内部类对象

Outer.Inner in = new Outer().new Inner();

2.当内部类在成员位置上,就可以被成员修饰符所修饰。

比如,private:将内部类在外部类中进行封装。

static:内部类就具备了static的特性。当内部类被静态修饰后,只能访问外部类中的静态成员,就出现了访问局限。

在外部类中如何访问静态内部类?new Ourter.Inner().function();

    在外部类中如何访问静态内部类中的静态成员呢? Ourter.Inner().function();

注意:当内部类中定义了静态成员,该内部类必须是静态的。

      当外部类中静态方法访问内部类时,内部类必须是静态的。

/*当描述事物时,事物的内部还有事物,该事物用内部类来描述。因为内部事物在使用外部事物的内容。*/
Class Body
{
private class heart()
{
}
Public void show()
{
New heart();
}
}

局部内部类不能定义为静态。

内部类定义在局部时:

1.      不可以被成员修饰符修饰

2.      可以直接访问外部类中的成员,因为还持有外部类中的引用。但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。

 

匿名内部类:

1.      匿名内部类其实就是内部类的简写形式。

2.      定义匿名内部类的前提:内部类必须是继承一个类或者实现接口。

3.      匿名内部类的格式:  new 父类或者接口(){定义子类的内容}.

4. 其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖,也可以理解为带内容的对象。

5.匿名内部类中定义的方法最好不要超过3个。



---------------------- ASP.Net+Android+IO开发S.Net培训、期待与您交流! ----------------------