多态

           ----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------

多态 
1.1. 抽象类 

为什么使用抽象类

1:定义Dog类

有颜色属性和叫的方法

2:定义Bird类

有颜色属性和叫的方法

3:定义其父类Animal

1:抽取共性颜色属性和叫的方法

1:颜色的属性可以使用默认初始化值。

2:叫的方法在父类中如何定义?

1:狗是旺旺

2:鸟是叽叽喳喳

3:可以将父类的方法定义为狗叫让鸟继承父类重写叫的方法

1:鸟怎么确定是否要重写父类方法。

2:不重写,编译和运行都没有问题,只是执行鸟叫的方法就会出现狗叫

4:父类的方法很难确定。

class Animal {

String color;

 

 void shout(){

 //如何定义呢?是旺旺还是叽叽喳喳?

 }

}

 

class Dog extends Animal {

 

void shout() {

System.out.println("旺旺");

}

 

}

 

class Bird extends Animal {

 

void shout() {

System.out.println("叽叽喳喳");

}

}

 

2:使用abstract

 

4:抽象类

1:当描述一个类的时候,如果不能确定功能函数如何定义,那么该类就可以定义为抽象类,功能函数应该描述为抽象函数。

5:抽象类的实现方式

1:定义animal类

1:定义叫的方法,无法确定方法体,不写方法体

1:public void shout (); 编译失败 

2:根据提示在shout的方法加入abstract修饰

1:编译失败,有新的提示

3:根据提示将类加入abstract修饰

1:编译通过

abstract class Animal {

String color;

 

abstract void shout();

}

 

class Dog extends Animal {

 

void shout() {

System.out.println("旺旺");

}

 

}

 

class Bird extends Animal {

 

void shout() {

System.out.println("叽叽喳喳");

}

}

 

6:抽象类的特点

1:有抽象函数的类,该类一定是抽象类。

2:抽象类中不一定要有抽象函数。

3:抽象类不能使用new创建对象

1:创建对象就是为了使用对象的功能,但是抽象类的方法,没有方法体。调用抽象方法没有意义.

4:抽象类主要为了提高代码的复用性,让子类继承来使用。

5:编译器强制子类实现抽象类父类的未实现的方法。

1:可以不实现,前提是子类的也要声明为抽象的。

7:抽象的优点

1:提高代码复用性

2:强制子类实现父类中没有实现的功能

3:提高代码的扩展性,便于后期的代码维护

例如:

8:抽象类不能创建对象,那么抽象类中是否有构造函数?

1:抽象类中一定有构造函数。主要为了初始化抽象类中的属性。通常由子类构造函数中通过super来访问。

9:final和abstract是否可以同时修饰一个类?  

一定不能同时修饰。

abstract class Animal {

 

String name;

 

// 抽象类可以有构造函数

Animal() {

 

}

 

Animal(String name) {

this.name = name;

}

 

abstract void shout();

 

}

 

class Dog extends Animal {

Dog() {

 

}

 

Dog(String name) {

super(name);

}

 

void shout() {

System.out.println("旺旺");

 

}

}

 

class Demo3 {

 

public static void main(String[] args) {

// 抽象类不能创建对象

// Animal a=new Animal();

Dog d = new Dog("旺财");

 

System.out.println();

}

}

 

2:抽象练习

1:定义抽象类MyShape(图形)

1:定义抽象方法获取图形的长度和面积

2:定义子类Rect继承父类MyShape   

1:定义自身特有的长和宽(成员变量)  width height;

2:实现父类未实现的函数。

3:定义子类 Circle实现父类MyShape

1:定义自身特有的半径和圆周率(使用常量)

2:实现父类为实现的方法。

 

/*

 }

 2:抽象练习 

 1:定义抽象类MyShape(图形)

 1:定义抽象方法获取图形的长度和面积

 2:定义子类Rect继承父类MyShape   

 1:定义自身特有的长和宽(成员变量)  width height;

 2:实现父类未实现的函数。

 3:定义子类 Circle实现父类MyShape

 1:定义自身特有的半径和圆周率(使用常量)

 2:实现父类为实现的方法。

 */

abstract class MyShape {

 

abstract double getLen();

 

abstract double getArea();

 

}

 

class Rect extends MyShape {

double width;

double height;

 

Rect() {

 

}

 

Rect(double width, double height) {

this.width = width;

this.height = height;

}

 

double getLen() {

return 2 * (width + height);

}

 

double getArea() {

return width * height;

}

}

 

class Circle extends MyShape {

double r;

public static final double PI = 3.14;

 

Circle() {

 

}

 

Circle(double r) {

this.r = r;

}

 

double getLen() {

return 2 * PI * r;

}

 

double getArea() {

return PI * r * r;

}

}

 

class Demo4 {

 

public static void main(String[] args) {

Rect r = new Rect(5, 5);

System.out.println(r.getLen());

System.out.println(r.getArea());

System.out.println();

 

Circle c = new Circle(5);

System.out.println(c.getLen());

System.out.println(c.getArea());

 

}

}

 

 

 
1.2. 接口 

1:没有接口会出现什么问题

1:定义铅笔类(Pencil),名字,写功能

2:定义带橡皮的铅笔(PencilWithEraser),写功能,擦除功能

1:带橡皮的铅笔is a 铅笔有继承关系,继承了铅笔

3:定义橡皮类(Eraser),擦除功能

1:带橡皮的铅笔有橡皮也可以继承橡皮,但java只支持单继承

4:由于java单继承的限制,无法解决现实中这类问题,那么就有了接口

5:发现带橡皮的铅笔是铅笔只是进行了功能加强,具备了擦除功能,可以把橡皮定义为接口

class Pencil {

 

String name;

 

Pencil() {

 

}

 

Pencil(String name) {

this.name = name;

}

 

void write() {

System.out.println("写字");

}

}

 

interface Eraser {

 

public static final String color = "白色";

 

public abstract void clean();

 

}

 

// 1:带橡皮的铅笔类继承铅笔类实现橡皮接口

class PencilWithEraser extends Pencil implements Eraser {

PencilWithEraser() {

 

}

 

PencilWithEraser(String name) {

super(name);

}

 

void write() {

System.out.println(name + ":考试专用");

}

 

public void clean() {

System.out.println(super.name + ":带橡皮的铅笔,就是好用");

}

}

 

class Demo6 {

 

public static void main(String[] args) {

 

PencilWithEraser pe = new PencilWithEraser("中华2B");

pe.write();

pe.clean();

 

System.out.println(pe.color);

System.out.println(PencilWithEraser.color);

 

}

}

 

2:接口是什么

1:接口usb接口,usb接口主要用于扩展笔记本的功能。

1:笔记本硬盘空间不够,使用usb移动硬盘解决问题。

2:java中接口:扩展java定义的类的功能,解决了java单继承的缺陷。

3:接口定义

interface关键字,用于定义一个接口类。

interface 接口名{

}

1:描述接口的属性(成员变量)

2:描述接口的行为(成员方法)

4:使用接口

implements 关键字可以使子类实现指定的多个接口

5:接口特点

1:接口中定义的所有属性默认是public static final的,即静态常量

1:即使静态常量,那么定义的时候必须赋值。

2:接口中定义的方法不能有方法体,接口中定义的方法默认添加public abstract

1:即接口不能定义实现方法

2:不添加public abstract也可以,默认添加,但不便于阅读 

3:接口不可以创建对象,因为接口有抽象方法。

1:new 接口编译报错。

4:接口要被子类实现,子类对接口中的抽象方法全部覆盖后子类才可以实例化,否则子类是一个抽象类。

5:接口可以被类多实现

interface A{

 

}

interface B{

 

}

interface C{

 

}

class D implements A,B,C{

 

}

 

6:如果实现类要访问接口中的成员,不能使用super关键字,因为两者没有显示的继承关系,可以使用接口名访问。

 

6:接口中是否有构造函数

1:一定没有

1:构造函数用于初始化非静态成员变量,接口中变量是静态常量。

7:接口练习

1:带橡皮的铅笔类继承铅笔类实现橡皮接口

8:接口使用细节

1:一个实现类可以同时实现多个接口

1:接口A,接口B ,实现类C可以同时实现A和B,例如implements A,B

2:接口之间可以进行多继承。

1:接口A,接口B,接口C ,接口C 可以同时继承A,和B,中间用逗号隔开。

2:接口与接口之间不能实现

3:定义接口A,B,C 类D实现 A,B ,C 创建D类对象,使用instanceof 比较A,B,C 全是true

1:如果一个实现类实现了很多接口,那么这个实现类的对象是这些接口的对象。

5:接口A,接口B 都定义了同名方法,实现类该如何实现。

1:只用实现一个方法即可。

1:接口中的同名方法,有重复代码,可以通过接口的继承来解决

9:抽象类是强迫子类重写父类方法,接口是增强实现类功能。 

 
1.3. 多态 

1:什么是多态

一个对象的多种状态

(老师)(员工)(儿子)

教师 a =make;

员工 b= make; 

2:多态体现

1:Father类

1:非静态成员变量x

2:静态成员变量y

3:非静态方法eat,方法体输出父类信息

4:静态方法speak();方法体输出父类信息 

2:Son类

1:非静态成员变量x

2:静态成员变量y

3:非静态方法eat,方法体输出子类信息

4:静态方法speak();方法体输出子类信息

class Father {

int x = 1;

static int y = 2;

 

void eat() {

System.out.println("开吃");

}

 

static void speak() {

System.out.println("小头爸爸");

}

}

 

class Son extends Father {

int x = 3;

static int y = 4;

 

void eat() {

System.out.println("大头儿子很能吃");

}

 

static void speak() {

System.out.println("大头儿子。");

}

}

 

class Demo10 {

 

public static void main(String[] args) {

 

Father f = new Son(); // 父类引用指向了子类对象。

System.out.println(f.x); // 1

System.out.println(f.y); // 2

 

f.eat(); // 输出的是子类的。

f.speak(); // 输出的是父类

}

}

 

3:Son类继承父类

1:创建Father f=new Son(); 

1:这就是父类引用指向了子类对象。

2:问f.x=?(非静态)

3:问f.y=?(静态)

4:问f.eat()输出的是子类还是父类信息?(非静态)

5:问f.speak()输出的是子类还是父类信息?(静态)

4:总结

1:当父类和子类具有相同的非静态成员变量,那么在多态下访问的是父类的成员变量

2:当父类和子类具有相同的静态成员变量,那么在多态下访问的是父类的静态成员变量

所以:父类和子类有相同的成员变量,多态下访问的是父类的成员变量。

3:当父类和子类具有相同的非静态方法(就是子类重写父类方法),多态下访问的是子类的成员方法。

4:当父类和子类具有相同的静态方法(就是子类重写父类静态方法),多态下访问的是父类的静态方法。

2:多态体现 

1:父类引用变量指向了子类的对象

2:父类引用也可以接受自己的子类对象

3:多态前提

1:类与类之间有关系,继承或者实现

4:多态弊端

1:提高扩展性,但是只能使用父类引用指向父类成员。

5:多态特点

非静态

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

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

3:总之成员函数在多态调用时,编译看左边,运行看右边。

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

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

6:多态练习

1:多态可以作为形参,接受范围更广的对象,避免函数重载过度使用。

1:定义功能(函数),该函数可以输出任何图形的面积和周长.根据输出任何图形的面积和周长。

1:定义抽象类abstract MyShape

1:定义抽象方法public abstract double getArea();

2:定义抽象方法public abstract double getLen();

 

2:定义Rect类继承MyShape

1:定义长和宽成员变量,double width height;

2:无参构造,有参构造。

3:实现父类方法。

3:定义Cricle类继承MyShape

1:定义半径成员变量,和PI常量 

2:无参构造,有参构造

3:实现父类方法。

4:定义静态方法计算任意图形的面积和周长

1:未知内容参与运算,不能确定用户传入何种图形,使用多态。

1:形参定义为 MyShape my

2:调用计算面积方法,和计算周长方法。并打印

2:使用多态特性,子类重写了父类非静态方法,会执行子类的方法。

/*

多态练习

1:多态可以作为形参,接受范围更广的对象,避免函数重载过度使用。

1:定义功能,根据输出任何图形的面积和周长。

子类重写了父类的抽象方法,多态下,会执行子类的非静态方法。

2:多态可以作为返回值类型。

获取任意一辆车对象

3:抽象类和接口都可以作为多态中的父类引用类型。

*/

abstract class MyShape{

public abstract double getArea();

public abstract double getLen();

}

class  Rect extends MyShape{

double width ;

double height;

Rect(){

}

Rect(double width ,double height){

this.width=width;

this.height=height;

}

public double getArea(){

return width*height;

}

public  double getLen(){

return 2*(width+height);

}

}

class Circle extends MyShape{

 double r;

 public static final double PI=3.14;

 

 Circle(){

 

 }

 

Circle(double r){

  this.r=r;

 }

public double getLen(){

  return 2*PI*r;

 }

public double getArea(){

  return PI*r*r;

 }

}

 

class Demo11{

 

public static void main(String[] args){

 

System.out.println();

print(new Rect(3,4)); //MyShape m =new Rect(3,4);

print(new Circle(3));

      }

      

      //根据用户传入的图形对象,计算出该图形的面积和周长

      //1:多态可以作为形参,接受范围更广的对象,避免函数重载过度使用。 

      public static void print(MyShape m){  

      System.out.println(m.getLen());

      System.out.println(m.getArea());

      }    

}

 

2:多态可以作为返回值类型。

定义一个汽车工厂类,获取任意一辆车对象,该工厂生产的汽车随机.

1:定义汽车类,有名字和颜色,提供有参和无参构造,有运行的行为。

2:定义Bmw类,继承Car类,提供无参构造和有参构造(super父类构造),重写父类运行行为。

3:定义Benz类,继承Car类,提供无参构造和有参构造(super父类构造),重写父类运行行为。

4:定义Bsj类,继承Car类,提供无参构造和有参构造(super父类构造),重写父类运行行为。

5:定义静态方法,汽车工厂,随机生产汽车。使用多态定义方法返回值类型。

1:使用(int)Math.round(Math.random()*2); 生成0-2之间随机数。

2:使用if else 判断,指定,0,1,2 new 不同汽车 并返回。

6:调用该方法,发现多态的好处。

*

 2:多态可以作为返回值类型。

 获取任意一辆车对象

 1:定义汽车类,有名字和颜色,提供有参和无参构造,有运行的行为。

 2:定义Bmw类,继承Car类,提供无参构造和有参构造(super父类构造),重写父类运行行为。

 3:定义Benz类,继承Car类,提供无参构造和有参构造(super父类构造),重写父类运行行为。

 4:定义Bsj类,继承Car类,提供无参构造和有参构造(super父类构造),重写父类运行行为。

 5:定义静态方法,汽车工厂,随机生产汽车。使用多态定义方法返回值类型。

 1:使用(int)Math.round(Math.random()*2); 生成0-2之间随机数。

 Math 类

 2:使用if else 判断,指定,0,1,2 new 不同汽车 并返回。

 6:调用该方法,发现多态的好处。

 */

class Car {

String name;

String color;

 

Car() {

 

}

 

Car(String name, String color) {

this.name = name;

this.color = color;

}

 

void run() {

System.out.println("跑跑。。。。");

}

}

 

class Bmw extends Car {

Bmw() {

 

}

 

Bmw(String name, String color) {

super(name, color);

}

 

void run() {

System.out.println("宝马很拉风。。。。");

}

}

 

class Benz extends Car {

Benz() {

 

}

 

Benz(String name, String color) {

super(name, color);

}

 

void run() {

System.out.println("奔驰商务首选。。。。");

}

}

 

class Bsj extends Car {

 

Bsj() {

 

}

 

Bsj(String name, String color) {

super(name, color);

}

 

void run() {

System.out.println("泡妞首选。。。。");

}

}

 

class Demo12 {

 

public static void main(String[] args) {

 

int x = 0;

while (x < 100) {

Car c = CarFactory();

c.run();

x++;

}

 

}

 

// 定义静态方法,汽车工厂,随机生产汽车。使用多态定义方法返回值类型。

// 使用随机数,0.1.2 if 0 bsj 1 bmw 2 bc

public static Car CarFactory() {

int x = (int) Math.round(Math.random() * 2);

 

if (0 == x) {

return new Bmw("宝马x6", "红色");

} else if (1 == x) {

return new Benz("奔驰", "黑色");

} else if (2 == x) {

return new Bsj("保时捷", "棕色");

} else {

return new Benz("Smart", "红色");

}

 

}

}

 

3:抽象类和接口都可以作为多态中的父类引用类型。

1:sun Arrays

6:多态之类型转型

1:案例定义Father类

1:定义method1和method2方法

2:定义Son类继承Father类

1:定义method1(重写父类method1)和method2方法,同时子类定义自身特有的method3方法.

3:创建Father f=new Son();

1: f.method1() 调用的子类或者父类?

2: f.method2() 编译和运行是否通过?

3: f.method3() 编译和运行是否通过?(编译报错)

 

4:如何在多态下,使用父类引用调用子类特有方法。

需要使用类类型装换.

1:基本类型转换:

1:自动:小->大

2:强制:大->小

2:类类型转换

前提:继承,或者实现.也就是必须有关系

1:自动:子类转父类

2:强转:父类转子类 

3:类型转换

1:Son s=(Son)f

2:s.method3();

/*

 如何在多态下,使用父类引用调用子类特有方法。

 1:基本类型转换:

 1:自动:小->大    int x=1 double d=x;

 2:强制:大->小    int y=(int)d;

 2:类类型转换

 前提:继承,必须有关系

 1:自动:子类转父类  Father f=new Son(); 

 2:强转:父类转子类  Son s=(Son)f; 

 1:类型转换

 1:Son s=(Son)f

 2:s.method3(); 

 */

class Father {

 

void method1() {

System.out.println("这是父类1");

}

 

void method2() {

System.out.println("这是父类2");

}

}

 

class Son extends Father {

void method1() {

System.out.println("这是子类1");

}

 

void method3() {

System.out.println("这是子类3");

}

}

 

class Demo14 {

 

public static void main(String[] args) {

Father f = new Son();

f.method1(); // 这是子类1

f.method2(); // 这是父类2

 

// f.method3(); //编译报错。

// 多态弊端,只能使用父类引用指向父类成员。

 

// 类类型转换

Son s = (Son) f;

s.method3();

 

System.out.println();

}

}

 

5:案例:测试类类型转换

本案例建立动物的继承体系.例如有父类Animal,子类Dog Fish等.每个子类有自己特有的行为.

请分别尝试,将Animal强制类型转换为Dog.

Dog强制类型转换为Fish,并观察发生了什么

 

1:定义Animal类颜色成员变量,无参构造,有参构造,run方法

2:定义Dog类,继承Animal,定义无参构造,有参构造(使用super调用父类有参构造),Dog的特有方法ProtectHome

3:定义Fish类,继承Animal,定义无参构造,有参构造(使用super调用父类有参构造),Fish特有方法swim

4:定义Bird类,继承Animal,定义无参构造,有参构造(使用super调用父类有参构造),Bird特有方法fly

5:使用多态,Animal a=new Dog();

6:调用Dog的特有方法,ProtectHome

1:类类型转换,Dog d=(Dog)a;

2:d.protectHome

7:非多态

1:Animal a=new Animal();

2:类类型转换

Dog d=(Dog)a;  

d.protectHome();

3:编译通过,运行出现异常

1:ClassCastException

8:多态例外

1:Animal  a=new Dog();

2:类类型转换

1:Fish f=(Fish)a;

2:f.fish();

3:编译通过,运行异常

1:ClassCastException

总结: 虽然是存在类与类之间继承关系,但是只有子类和父类之间有关系.但是鸟不能转为狗,狗不能转为鱼,他们之间没有关系。

class Animal {

String color;

 

Animal() {

 

}

 

Animal(String color) {

this.color = color;

}

 

void run() {

System.out.println("跑跑");

}

}

 

class Dog extends Animal {

Dog() {

 

}

 

Dog(String color) {

super(color);

}

 

void run() {

System.out.println("狗儿跑跑");

}

 

void protectHome() {

System.out.println("旺旺,看家");

}

}

 

class Fish extends Animal {

Fish() {

 

}

 

Fish(String color) {

super(color);

}

 

void run() {

System.out.println("鱼儿水中游");

}

 

void swim() {

System.out.println("鱼儿游泳");

}

 

}

 

class Demo15 {

 

public static void main(String[] args) {

 

Animal ani = new Dog();

// ani.protectHome();

// 正常转换

Dog d = (Dog) ani;

d.protectHome();

 

// 多态例外

Animal an = new Animal();

// ClassCastException

// Dog d=(Dog)an

 

// 多态例外

Animal dog = new Dog();

// ClassCastException

// Fish f = (Fish) dog;

 

}

}

 

6:案例2

1:定义一功能,接收用户传入动物,根据用于传入的具体动物,执行该动物特有的方法

2:使用多态,方法形参,不能确定用户传入的是那种动物

3:使用instanceof 关键字,判断具体是何种动物,

4:类转换,执行该动物的特有方法。

package oop04;

 

/*

 案例2

 1:定义一功能,接收用户传入动物,根据用于传入的具体动物,执行该动物特有的方法

 2:使用多态,方法形参,不能确定用户传入的是那种动物

 3:使用instanceof 关键字,判断具体是何种动物,

 4:类转换,执行该动物的特有方法。

 */

class Animal {

String color;

 

Animal() {

 

}

 

Animal(String color) {

this.color = color;

}

 

void run() {

System.out.println("跑跑");

}

}

 

class Dog extends Animal {

Dog() {

 

}

 

Dog(String color) {

super(color);

}

 

void run() {

System.out.println("狗儿跑跑");

}

 

void protectHome() {

System.out.println("旺旺,看家");

}

}

 

class Fish extends Animal {

Fish() {

 

}

 

Fish(String color) {

super(color);

}

 

void run() {

System.out.println("鱼儿水中游");

}

 

void swim() {

System.out.println("鱼儿游泳");

}

 

}

 

class Bird extends Animal {

Bird() {

 

}

 

Bird(String color) {

super(color);

}

 

void run() {

System.out.println("鸟儿空中飞");

}

 

void fly() {

System.out.println("我是一只小小鸟。。。。");

}

}

 

class Demo16 {

 

public static void main(String[] args) {

 

System.out.println();

doSomething(new Dog());

doSomething(new Bird());

doSomething(new Fish());

}

 

// 定义一功能,接收用户传入动物,根据用于传入的具体动物,执行该动物特有的方法

public static void doSomething(Animal a) {

if (a instanceof Dog) {

Dog d = (Dog) a;

d.protectHome();

} else if (a instanceof Fish) {

Fish f = (Fish) a;

f.swim();

} else if (a instanceof Bird) {

Bird b = (Bird) a;

b.fly();

} else {

System.out.println("over");

}

}

}

 

 
1.4. 内部类   

inner class nested class

定义在类中的类

快速体验:

Outer类中有Inner类 Inner类就是内部类

class Outer {

private int x = 1;

 

// 成员内部类

private class Inner {

int y = 2;

int x = 3;

 

void innerPrint() {

System.out.println("内部类" + y); // 2

System.out.println(this.x); // 3

 

}

}

 

void outPrint() {

System.out.println("外部类" + x);

// 外部类的成员方法上,创建成员内部类对象。

Inner n = new Inner();

n.innerPrint();

}

}

 

class Demo1 {

 

public static void main(String[] args) {

Outer out = new Outer();

out.outPrint();

}

}

 

内部类分类

成员内部类,静态内部类(嵌套类),匿名内部类

 
1.4.1. 成员内部类 

1:成员内部类和成员变量和成员方法是并列的。

2:成员内部类也是类,也可以定义成员变量和成员方法 

内部类和外部类的相互访问

在外部类的成员函数中创建内部类的对象,直接访问内部类的方法

案例

1:创建Outer类,是外部类,定义成员变量(例如 int x)和成员方法(例如:print方法)。

1:在Outer中,定义名字为Inner的内部类,定义成员变量(int y)和成员方法(例如innerPrint)。

2:创建内部类对象

3:外部类中调用内部类的成员方法

1:Outer类的print方法,在该方法中创建Inner对象,并调用Inner的方法innerPrint

4:内部类可以访问外部类的成员

1:外部类成员变量,在内部类中可以直接访问

5:内部类可以直接访问外部类的成员。

6:外部类和内部类定义了同名的成员变量(例如 int x=1;)

1:在内部类中,先找内部类中,没有找到再找外部类的。

2:如果内部类一定要访问外部类的成员

1:使用this 是Inner类的对象

2:使用this.Outer可以访问到外部类的成员变量。

其他类中直接创建内部类对象

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

看到这里其实就应该明白,内部类对象持有有一个所在外部类对象引用.所以在创建内部类对象时,要先创建外部类对象.

class Outer {

private int x = 1;

 

// 成员内部类

class Inner {

int y = 2;

int x = 3;

 

void innerPrint() {

System.out.println("内部类" + y); // 2

System.out.println(this.x); // 3

System.out.println(Outer.this.x);

 

}

}

 

void outPrint() {

System.out.println("外部类" + x);

// 外部类的成员方法上,创建成员内部类对象。

Inner n = new Inner();

n.innerPrint();

}

}

 

class Demo1 {

 

public static void main(String[] args) {

Outer out = new Outer();

out.outPrint();

// 成员内部类创建方式

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

in.innerPrint();

}

}

 

2:为什么定义内部类

1:成员内部类作为外部类的成员,可以直接访问外部类的所有成员。

3:成员内部类被private修饰

1:外部类的成员变量和成员方法都可以被private修饰,成员内部类是否可以。

2:案例

1:外部类Outer,定义成员变量成员方法(例如int x, outerPrint())

2:内部类Inner,定义成员变量和成员方法(例如int x,interPrint())

3:Inner被private修饰

4:在Outer 类的outerPrint()方法中创建Inner 对象,调用Inner 的interPrint()方法

1:编译通过,运行没有问题。

5:在其他类中创建内部类Inner对象

1:编译失败

3:被private修饰的成员内部类只能在内部类所在的外部类中创建和访问。

class Outer {

private int x = 1;

 

// 成员内部类

private class Inner {

int y = 2;

int x = 3;

 

void innerPrint() {

System.out.println("内部类" + y); // 2

System.out.println(this.x); // 3

System.out.println(Outer.this.x);

 

}

}

 

void outPrint() {

System.out.println("外部类" + x);

// 外部类的成员方法上,创建成员内部类对象。

Inner n = new Inner();

n.innerPrint();

}

}

 

class Demo1 {

 

public static void main(String[] args) {

Outer out = new Outer();

out.outPrint();

// 被private修饰的成员内部类只能在内部类所在的外部类中创建和访问。

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

// in.innerPrint();

}

}

 

 
1.4.2. 嵌套类(静态内部类) 

成员内部类被static修饰

1:案例

1:外部类Outer,定义成员变量成员方法(例如int x, outerPrint())

2:内部类Inner,定义成员变量和成员方法(例如int x,interPrint())

3:内部类的成员变量使用static修饰

1:编译失败,提示内部类不能有静态声明

4:将内部类Inner使用static修饰

5:在Outer 类的outerPrint()方法中创建Inner 对象,调用Inner 的interPrint()方法

1:编译通过,运行没有问题。

6:在其他类中创建静态内部类Inner对象

1:编译提示,限定的新静态类。

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

2:如果成员内部类包含静态成员,java规定内部类必须声明为静态的。

3:访问形式

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

注意: 很显然创建静态内部类对象不需要外部类的对象.但是静态内部类不可以访问外部类的非静态成员.(静态不能访问非静态)可以将静态类理解为所在外部类的成员.可以直接通过类名访问静态类.

/*

 成员内部类static修饰

 如果成员内部类包含静态成员,java规定内部类必须声明为静态的。

 访问形式

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

 

 */

class Outer {

int x = 2;

static int y = 1;

 

// 成员内部类被static修饰

static class Inner {

int y = 2;

int x = 3;

static int z = 5; // 内部类有静态成员,类也需要是static

 

void innerPrint() {

System.out.println("内部类" + y); // 2

System.out.println(this.x); // 3

System.out.println(z);

}

}

 

void outPrint() {

System.out.println("外部类" + x);

Inner n = new Inner();

n.innerPrint();

}

}

 

class Demo2 {

 

public static void main(String[] args) {

Outer out = new Outer();

 

// 静态内部类创建方式

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

in.innerPrint();

 

}

}

 

 

 
1.4.3. 局部内部类 

1:案例定义局部内部类

2:外部类Outer,定义成员变量成员方法(例如int x, outerPrint())

3:在outerPrint()方法中定义一个类(例如LocalHost),该类有成员变量(例如int y),有方法interPrint();

4:LocalHost类就叫做局部内部类,和局部变量int x是并列的。

5:创建局部内部类对象(LocalHost类的对象)

1:在outerPrint()方法中创建LocalHost类的对象并调用interPrint方法。

2:编译通过,正常运行。

6:局部内部类访问所在方法的局部变量x

1:在outerPrint()方法中创建LocalHost类的对象并调用interPrint方法。

2:局部内部类(LocalHost类)的对象调用interPrint方法访问outerPrint方法中的局部变量x

1:编译报错内部类访问局部变量,需要声明为最终类型。

3:局部内部类访问所在方法的局部变量,该变量需要是final的。

7:为什么加final

1:生命周期

注意:方法的局部变量位于栈上,只存在于该方法的声明周期内,随着方法的运行而存在,方法的消失而消失.当方法结束时,栈内存会释放,变量消失.但是即使方法运行完毕,在该方法中创建的内部类对象仍然可能存活于堆内存中(例如将局部内部类的引用传递到其他代码中).由于生命周期的不同,所以内部类对象不能使用它们,如果一定要使用就需要将局部变量声明为final的.

注意: 局部内部类对象只能在该类所在的方法中实例化.

class Outer {

int x = 2;

static int y = 1;

 

void outPrint() {

// 局部内部类访问局部变量需要使用final修饰

final int y = 2;

 

class LocalClass {

int x = 3;

 

void innerPrint() {

System.out.println("局部内部类" + x);

System.out.println(y);

}

}

System.out.println("外部类" + x);

 

LocalClass lc = new LocalClass();

lc.innerPrint();

 

}

}

 

class Demo3 {

 

public static void main(String[] args) {

Outer out = new Outer();

out.outPrint();

 

System.out.println();

}

}

 

 
1.4.4. 匿名内部类 

案例

2:定义接口MyInterface,成员变量(静态常量必须初始化)和方法print(默认public abstract)。

2:外部类Outer,定义成员变量成员方法(例如int x, outerPrint())

3:内部类Inner 实现MyInterface接口,实现print方法。

4:创建内部类对象

在outerPrint方法中创建内部类对象,调用内部类的方法。

5:此种案例的代码可以使用匿名内部类来实现。

6:修改代码,使用匿名内部类

1:在outerPrint方法中 new MyInterface(){}; 花括号中需要实现接口的print方法

2:接口不能new。

1:这里不是new接口,是在创建一个接口的实现类,只不过该接口的实现类没有名字。

3:new MyInterface(){};  其实就是内部类的一种替换格式。

1:调用print方法new MyInterface(){}.print(); 

2:匿名内部类是内部类的简写格式

3:使用匿名内部类的前提

1:内部类要继承一个类或者实现接口

4:格式 new 父类或接口(){子类内容}

5:匿名内部类就是一个匿名子类对象

6:如果只调用一个方法可以new MyInterface(){}.print(); 形式调用,如果接口或者父类中有2个以上的方法,就需要起名字了。 

1:MyInterface in=new MyInterface(){};

2:in.print();

3:多态的体现。

interface MyInterface {

public static final int x = 3;

 

public abstract void print();

 

public abstract void run();

}

 

class Outer {

int x = 2;

static int y = 1;

 

void outPrint() {

final int y = 2;

 

class LocalClass implements MyInterface {

 

public void print() {

System.out.println("局部内部类。。。。");

}

 

public void run() {

System.out.println("跑跑。。。");

 

}

}

 

LocalClass lc = new LocalClass();

lc.print();

 

}

}

 

class Demo4 {

 

public static void main(String[] args) {

new Outer().outPrint();

 

System.out.println();

}

}

 

interface MyInterface {

public static final int x = 3;

 

public abstract void print();

 

}

 

class Outer {

int x = 2;

static int y = 1;

 

void outPrint() {

final int y = 2;

 

// class LocalClass implements MyInterface {

//

// public void print() {

// System.out.println("局部内部类。。。。");

// }

//

//

// }

// }

//

// LocalClass lc = new LocalClass();

// lc.print();

        //是对上述注释的简写

new MyInterface() {

 

public void print() {

System.out.println("匿名内部类。。。。");

}

}.print();

 

 

 

}

}

 

class Demo4 {

 

public static void main(String[] args) {

new Outer().outPrint();

 

System.out.println();

}

}

 

转载于:https://www.cnblogs.com/monkyo/p/5064735.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值