局部位置(比如方法内)
一、局部内部类
① 可以直接访问外部类中的所有成员,包含私有的的成员。② 不能添加访问修饰符,本质是一个局部变量,局部变量是不能使用访问修饰符的,可以使用final③ 作用域:只有在定义该内部类的方法中或代码块中可以访问。④ 局部内部类可以直接访问外部类的成员⑤ 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,可以使用:外部类名.this.成员 进行访问 二、匿名内部类【超重要】
① 匿名内部类的底层是系统创建一个类实现了接口或继承了父类,系统会分配类名② 匿名内部类使用一次就不能再使用了,但是创建的这个对象是还可以继续使用的。③ 匿名内部类可以实现接口,也可以继承类,原理是一样的。④ 基于抽象类或接口的匿名内部类必须实现抽象方法⑤ 可以直接访问外部类的所有成员,包含私有的成员⑥ 不能添加访问修饰符,他的本质是一个局部变量,作用域也是定义的方法体或代码块中⑦ 如果外部类和匿名内部类的成员重名时,匿名内部类需要访问,则遵循就近原则,如果想访问外部类的成员,可以使用:外部类名.this.成员 进行访问 成员位置(类成员位置)
三、成员内部类
① 可以直接访问外部类的所有成员,包含私有的② 可以添加任意访问修饰符,成员内部类的本质是一个成员③ 成员内部类的作用域和其他成员一样,可以在外部类中创建对象,如果有权限则也可以在其他外部类中可以使用。④ 成员内部类在其他外部类创建对象的三种方式⑤ 如果外部类和内部类成员重名时,内部类访问则按照就近原则,如果想访问外部类成员,可以使用:外部类名.this.成员 四、静态内部类
① 可以访问外部类的所有静态成员,但是不能直接访问非静态成员② 可以添加任意访问修饰符,静态内部类本质是一个静态成员。③ 作用域:同其他成员,为类的整体④ 其他外部类访问静态内部类的方式:⑤ 如果外部类和静态内部类成员重名时,静态内部类访问则按照就近原则,如果想访问外部类成员,可以使用:外部类名.成员
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。
内部类最大的特点就是可以直接访问私有属性,并且可以体现类的包含关系。
内部类的本质还是一个类。
基本语法:
class 外部类类名 { class 内部类类名{ } } class 外部其他类类名{ }局部位置(比如方法内) 一、局部内部类
定义在外部类的局部位置,比如方法中,并且有类名。
语法格式:
class 外部类名 { public 返回值 方法名(参数列表) { // 局部内部类是定义在外部类的局部位置,通常是方法 class 内部类名 { } } }① 可以直接访问外部类中的所有成员,包含私有的的成员。
class Outher { private int n1 = 100; public void m1() { // 内部类 class Inner { // 内部类的方法 public void f1() { // 内部类可以直接访问外部类的私有成员 System.out.println("n1 = " + n1); } } } }② 不能添加访问修饰符,本质是一个局部变量,局部变量是不能使用访问修饰符的,可以使用final
因为final修饰符局部变量也可以使用
class Outher { public void m1() { // public class Inner {} 编译不能通过 // final class Inner {} 编译可以通过,但是此内部类不能被继承 class Inner{} // 编译可以通过,此内部类可以被继承 class InnerZi extends Inner {} // 内部类的继承内部类 } }③ 作用域:只有在定义该内部类的方法中或代码块中可以访问。
class Outher { { class Inner{} // 代码块中也可以定义内部类 } public void m1() { class Inner{} Inner inner = new Inner(); // 使用内部类,创建内部类对象,注意代码顺序 } public void m2() { // Inner inner = new Inner(); 另一个方法就不能访问其他方法中的内部类 } }④ 局部内部类可以直接访问外部类的成员
class Outher { private int n1 = 100; public void m1() { class Inner{ public void f1() { System.out.println("n1 = " + n1); // 访问外部类的成员变量 m2(); // 访问外部类的成员方法 } } } public void m2() {} }⑤ 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,可以使用:外部类名.this.成员 进行访问
如果不加this关键字的话调用的是静态的成员,外部类名.this的本质是外部类对象,谁调用就是谁
class Outher { // 外部类的n1成员变量 private int n1 = 100; public void m1() { class Inner{ // 内部类的n1成员变量 private int n1 = 200; public void f1() { // 方法同理 System.out.println("n1 = " + n1); // 访问内部类的成员变量 System.out.println("n1 = " + Outher.this.n1); // 访问外部类的成员变量 } } } }二、匿名内部类【超重要】
匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
匿名内部类没有名字,但是系统会分配一个名字,匿名内部类同时还是一个对象。
语法格式:
new 类名或者接口名(参数列表){ // 类体 };
举个例子:
正常的接口实现方式:
interface A { // 一个接口 public void eat(); } class B implements A { // 接口的实现类 @Override public void eat() { System.out.println("我就喜欢吃吃吃"); } } class Outher02 { public void method() { // 创建接口实现类对象 A a = new B(); // 调用接口中的方法 a.eat(); } }
匿名内部类实现方式:
如果实现类只使用一次的话,这样会方便很多。
interface A { // 一个接口 public void eat(); } class Fa { // 一个普通的类 public Fa(String name) {} public void test() {} } class Outher02 { // 外部类 public void method() { // 创建接口实现类对象 A a = new A(){ // 匿名内部类 @Override public void eat() { System.out.println("我就喜欢吃吃吃"); } }; // 调用接口中的方法 a.eat(); } }① 匿名内部类的底层是系统创建一个类实现了接口或继承了父类,系统会分配类名
在上面的例子中,编译时会生成一个新的类,实现了A接口,这个类的类名是外部类类名 + $ + 编号,比如这里就是Outher02$1
class Outher02 { // 外部类 public void method() { // 创建接口实现类对象 A a = new A(){ // 匿名内部类 @Override public void eat() { System.out.println("我就喜欢吃吃吃"); } }; // 调用接口中的方法 a.eat(); // 查看变量a的运行类型 System.out.println(a.getClass()); } }
通过以上代码,可以看到以下结果
所以在底层,会分配一个匿名类,这个类的名字是Outher02$1,类的方法体就是匿名内部类的方法体,应该是下面这样:
class Outher02 implements A { // 系统底层创建的接口的实现类 @Override public void eat() { System.out.println("我就喜欢吃吃吃"); } }
然后创建对象的时候将该对象的引用返回给给变量a,这是变量a的运行类型是A接口,编译类型实际上是Outher02$1实现类。
② 匿名内部类使用一次就不能再使用了,但是创建的这个对象是还可以继续使用的。class Outher02 { // 外部类 public void method() { A a = new A(){ // 匿名内部类 @Override public void eat() { System.out.println("我就喜欢吃吃吃"); } }; a.eat(); a.eat(); a.eat(); } }
对象可以多次使用,但是匿名内部类就不能再创建对象了,就算new Outher02$1()也不行。
③ 匿名内部类可以实现接口,也可以继承类,原理是一样的。这里创建的fu对象的运行类型和编译类型都是Fu这个类
class Fu { // 一个普通的类 public Fu(String name) {} public void test() {} } class Outher02 { // 外部类 private int n = 100; public void method() { Fu fu = new Fu("zhangsan"); } }
但是如果将创建的对象变成匿名内部类对象的话,这里的运行类型是Fu,而编译类型就是匿名内部类对象了,jdk底层也会为其创建一个一次性的类,类名可能就是Outher02$2
class Outher02 { // 外部类 private int n = 100; public void method() { Fu fu = new Fu("zhangsan") { }; } }
加上大括号之后就是匿名内部类,相当于继承了new的这个类,所以底层生成的这个类应该是:
class Outher02 extends Fu{ public Outher02(String name) { super(name); } }
如果在大括号中重写了父类的方法,则也是按照动态绑定机制使用编译类型的方法。
④ 基于抽象类或接口的匿名内部类必须实现抽象方法abstract class Fu { // 一个抽象类 public abstract void test(); } class Outher02 { // 外部类 private int n = 100; public void method() { // 匿名内部类 Fu fu = new Fu() { // 实现抽象方法 @Override public void test() { } }; } }⑤ 可以直接访问外部类的所有成员,包含私有的成员
同上局部内部类的第一条
⑥ 不能添加访问修饰符,他的本质是一个局部变量,作用域也是定义的方法体或代码块中同上局部内部类的第二条和第三条
⑦ 如果外部类和匿名内部类的成员重名时,匿名内部类需要访问,则遵循就近原则,如果想访问外部类的成员,可以使用:外部类名.this.成员 进行访问同上局部内部类第五条
成员位置(类成员位置) 三、成员内部类成员内部类是定义在外部类的成员位置,并且没有static修饰
语法格式:
class 外部类 { 访问修饰符 class 内部类{ } }① 可以直接访问外部类的所有成员,包含私有的
成员内部类可以理解为类的一个成员,类中的成员是可以访问该类的其他成员的。
class Outher03 { private int n1 = 300; public String name = "zhangsan"; // 成员内部类 class Inner { public void say() { // 可以访问外部类的所有成员,包含私有的 System.out.println(n1); System.out.println(name); } } }② 可以添加任意访问修饰符,成员内部类的本质是一个成员
class Outher03 { public class Inner01 { } protected class Inner02 { } class Inner03 { } private class Inner04 { } }③ 成员内部类的作用域和其他成员一样,可以在外部类中创建对象,如果有权限则也可以在其他外部类中可以使用。
// 定义类: public class Person { private boolean live = true; // 如果成员内部类是私有的,则其他外部类无法创建该内部类的对象 public class Heart { public void jump() { // 直接访问外部类成员 if (live) { System.out.println("心脏在跳动"); } else { System.out.println("心脏不跳了"); } } } public void m1() { // 成员内部类可以类外部类中直接创建对象调用并使用 Heart heart = new Heart(); heart.jump(); } } // 定义测试类: class InnerDemo { public static void main(String[] args) { // 成员内部类在其他外部类中,需要先创建外部类的对象,通过外部类的对象再创建内部类的对象,才可调用并使用 // 创建外部类对象 Person p = new Person(); // 创建内部类对象 Person.Heart heart = p.new Heart(); // 调用内部类方法 heart.jump(); } } // 输出结果: // 心脏在跳动④ 成员内部类在其他外部类创建对象的三种方式
第一种: 外部类名.内部类名 变量名 = new 外部类().new 成员内部类();
class Outher03 { // 成员内部类 public class Inner01 { } } class Test { // 创建成员内部类对象的测试方法 public void test() { Outher03.Inner01 inner01 = new Outher03().new Inner01(); } }
第二种: 外部类名 外部类变量名 = new 外部类();
外部类名.内部类名 内部类变量名 = 外部类变量名.new 内部类();
class Outher03 { // 成员内部类 public class Inner01 { } } class Test { // 创建成员内部类对象的测试方法 public void test() { Outher03 outher03 = new Outher03(); Outher03.Inner01 inner01 = outher03.new Inner01(); } }
第三种: 使用get方法
class Outher03 { // 成员内部类 public class Inner01 { } // get方法 public Inner01 getInner() { return new Inner01(); } } class Test { // 创建成员内部类对象的测试方法 public void test() { Outher03 outher03 = new Outher03(); Outher03.Inner01 inner = outher03.getInner(); } }⑤ 如果外部类和内部类成员重名时,内部类访问则按照就近原则,如果想访问外部类成员,可以使用:外部类名.this.成员
同上局部内部类第五条
四、静态内部类静态内部类是定义在外部类的成员位置,并且有static修饰
class 外部类 { 访问修饰符 static class 内部类 { } }① 可以访问外部类的所有静态成员,但是不能直接访问非静态成员
class Outher04 { private static String name = "lisi"; private int age = 10; static class Inner04 { // 静态内部类访问外部类的静态成员,非静态成员无法直接访问 public void m1() { System.out.println(name); } } }② 可以添加任意访问修饰符,静态内部类本质是一个静态成员。
同上成员内部类的第二条
③ 作用域:同其他成员,为类的整体class Outher04 { private static String name = "lisi"; static class Inner04 { public void m1() { System.out.println(name); } } public void say() { // 外部类访问静态内部类的非静态成员方法 Inner04 inner04 = new Inner04(); inner04.m1(); } }
class Outher04 { private static String name = "lisi"; static class Inner04 { public static void m2() { System.out.println(name); } } public void say02() { // 外部类访问静态内部类的静态成员方法 Inner04.m2(); } }④ 其他外部类访问静态内部类的方式:
第一种: 外部类名.静态内部类名 变量名 = new 外部类.内部类();
跟成员内部类是不一样
class Outher04 { static class Inner04 { public void m1() { } } } class Test02 { public void test() { Outher04.Inner04 inner04 = new Outher04.Inner04(); } }
第二种: 使用get方法
get方法也可以设计成静态的,或许会更方便一些。
class Outher04 { static class Inner04 { public void m1() { } } // get方法 public Inner04 getInner04(){ return new Inner04(); } } class Test02 { public void test() { Outher04 outher04 = new Outher04(); Outher04.Inner04 inner04 = outher04.getInner04(); } }⑤ 如果外部类和静态内部类成员重名时,静态内部类访问则按照就近原则,如果想访问外部类成员,可以使用:外部类名.成员
同上局部内部类第五条,只不过这里是静态的,无需使用this
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)