概述
将一个类定义在另一个类的里面,里面的那个类就称为内部类(内置类,嵌套类)
分析事物A时,发现该事物A描述中还有事物B,而且这个事物B还在访问被描述事物A的内容,将事物B定义成内部类来描述。
特点
- 内部类可以直接访问外部类中的成员;
- 外部类要访问内部类,必须建立内部类的对象;
举例:
package innerdemo; public class InnerDemo1 { public static void main(String[] args) { Outer.Inner in = new Outer().new Inner(); // 直接访问内部类的方法 in.show(); Outer o = new Outer();// o.method(); } } class Outer{ private int num = 3; // 内部类 class Inner{ void show(){ num = 100; System.out.println("内部类run..."+num); } } public void method(){ Inner in = new Inner(); //外部类要访问内部类,必须建立内部类的对象; in.show(); } }
修饰符
直接访问外部类中的内部类中的成员:(不多见)
外部类名.内部类名 变量名 = new 外部类名(). new 内部类名();
Outer.Inner in = new Outer().new Inner();
in.show();
内部类是静态的类,相当于一个外部类。外部类只要一加载,内部类就存在了,所以直接new一个内部类对象出来;
Outer.Inner in1 = new Outer.Inner();
public class InnerClassDemo { public static void main(String[] args) { // 内部类是静态的。相当于一个外部类 Outer.Inner in1 = new Outer.Inner(); in1.show(); } } class Outer{ private static int num = 3; // 内部类 static class Inner{ void show(){ System.out.println("内部类run..."+num); } } }
如果内部类是静态的,成员是静态的,就不需要对象了。如果内部类中定义了静态成员,该内部类也必须是静态的。
package java_demo_2; public class InnerClassDemo { public static void main(String[] args) { Outer.Inner.function(); } } class Outer{ private static int num = 3; // 内部类 static class Inner{ void show(){ System.out.println("内部类run..."+num); } public static void function(){ System.out.println("内部类是静态的,成员也是静态的,不需要创建对象"+num); } } }
细节
package java_demo_2; public class InnerClassDemo { public static void main(String[] args) { new Outer().method(); } class Outer{ int num = 3; // 内部类 class Inner{ int num = 4; void show(){ int num = 5; System.out.println(num); // num 5 System.out.println(this.num); // 4 局部和成员变量重名 System.out.println(Outer.this.num); // 3 } } void method(){ new Inner().show(); } }
为什么内部类能直接访问外部类中成员呢?
那是因为内部类持有了外部类的引用。外部类名.this
局部内部类
内部类可以存放在局部位置上,可以放在方法中,放在代码块中。
class Outer1{ int num = 3; void method(){ // 内部类在方法中 class Inner{ void show(){ System.out.println("方法中的内部类:"+num); } } // 创建对象 Inner in = new Inner(); in.show(); } { // 内部类在代码块中 class Inner2{ void show(){ System.out.println("代码块中的内部类:" + num); } } Inner2 in2 = new Inner2(); in2.show(); } }
内部类在局部位置上只能访问局部中被final修饰的局部变量;
class Outer{ int num = 3; void method(){ final int x = 9; // 这个好像都行 int x = 9 不报错; class Inner{ void show(){ System.out.println("show..."+x); // 内部类在局部位置上只能访问局部中被final修饰的局部变量; } } // 创建对象 Inner in = new Inner(); in.show(); } }
匿名内部类
概述
内部类的简写格式。要简写,必须和外部类有关系。必须有前提:内部类必须继承或者实现一个外部类或者接口。
格式: new 父类or接口(){子类内容};
匿名内部类,其实就是一个匿名子类对象;这个对象比较胖。
按道理要先继承父类,重构方法,再创建对象调用方法如:
class Inner extends InnerDemo{ void show() { System.out.println("内部类run..." + num); } } public void method() { new Inner().show(); }
现在直接在方法里,进行new 父类(){重构方法;}
new InnerDemo(){ // 匿名内部类,new 他爹(){把方法重写;} void show(){ System.out.println("show..."+num); } }
具体代码如下:
public class InnerClassDemo { public static void main(String[] args) { new Outer().method(); } } // 抽象类 abstract class InnerDemo{ abstract void show(); } class Outer { private int num = 3; // 内部类 // class Inner { // void show() { // System.out.println("内部类run..." + num); // } // // } public void method() { // new Inner().show(); new InnerDemo(){ // 匿名内部类,new 他爹(){把方法重写;} void show(){ System.out.println("show..."+num); } }.show(); } }
应用
注释部分:普通内部类继承外部接口时代码:
interface Inter{ void show1(); void show2(); } class Outer { private int num = 3; // 内部类 /* class Inner implements Inter { public void show1(){ } public void show2(){ } } */ public void method(){ // Inner in = new Inner(); // in.show1(); // in.show2(); Inter in = new Inter(){ public void show1(){ } public void show2(){ } }; in.show1(); in.show2(); } }
通常的使用场景之一:当函数参数是接口类型时,而且接口中的方法不超过三个,可以用匿名内部类作为实际参数进行传递。
// 正常写 public class InnerClassDemo { public static void main(String[] args) { show(new InterImpl()); } public static void show(Inter in){ in.show1(); in.show2(); } } interface Inter{ void show1(); void show2(); } class InterImpl implements Inter{ public void show1(){} public void show2(){} } // 简写,将匿名内作为实际参数传递 public class InnerClassDemo { public static void main(String[] args) { show(new Inter(){ public void show1(){} public void show2(){} }); } public static void show(Inter in){ in.show1(); in.show2(); } } //接口 interface Inter{ void show1(); void show2(); }
分类
- 成员内部类(静态内部类和非静态内部类)
- 局部内部类
- 匿名内部类
成员内部类
- 静态内部类:直接通过外部类调用静态内部类的构造器
- 非静态内部类:先创建外部类的对象,再通过外部类的对象调用内部类的构造器或者
外部类名.内部类名 对象名 = new 外部类型().new 内部类型();
package innerdemo; /** * @ClassName: InnerClassDemo * @author: benjamin * @version: 1.0 * @description: TODO * @createTime: 2019/06/11/10:11 */ public class InnerClassDemo { public static void main(String[] args) { // 创建静态内部类的对象 Person.Dog d = new Person.Dog();// 直接通过外部类调用静态内部类的构造器 //创建非静态内部类的对象 // Person.Bird b = new Person().new Bird(); Person p = new Person(); Person.Bird b = p.new Bird();// 通过外部类的对象调用内部类的构造器 b.info(); } } class Person{ String name; int age; // 非静态成员内部类 class Bird{ String name; int id; public Bird(){ } public void setName(String name){ this.name = name; } public void info(){ show(); } } // 静态成员内部类 static class Dog{ String name; int id; public Dog(){ } public void setName(String name){ this.name = name; } public void info(){ } } // 外部类的成员方法 public void show(){ System.out.println("我是外部类的show()方法"); } }
局部内部类:常常使用一个方法,使其返回值为某个类或接口的对象,而这个类或接口在方法内部创建。举例:
匿名内部类:
举例:
class OuterJu{ // 局部内部类的使用 public Comparable getComparable(){ //1.创建一个实现Comparable接口的类:局部内部类 class MyComparable implements Comparable{ @Override public int compareTo(Object o) { return 0; } } // 2. 返回一个实现类的对象 return new MyComparable(); } // 匿名内部类的使用 public Comparable getComparable1(){ //返回一个实现Comparable接口的匿名内部类的对象 return new Comparable() { @Override public int compareTo(Object o) { return 0; } }; } }
细节
细节1
主函数会报错,因为无法访问非静态类,而且由于是静态不能采用this.new Inner()
方法:需要将Inner定义成静态类;
package java_demo_2; /** * @ClassName: InnerClassDemo5 * @author: benjamin * @version: 1.0 * @description: TODO * @createTime: 2019/04/13/22:28 */ public class InnerClassDemo5 { class Inner{// 如果不定义成静态,主函数会报错; } public static void main(String[] args) { new Inner(); //无法从静态上下文中引用非静态 变量 this // 因为主函数是静态的; } public void method(){ new Inner(); // 正确 } public static void show(Inter in){ in.show1(); in.show2(); } } interface Inter{ void show1(); void show2(); }
细节2:
// 正确的 package java_demo_2; public class InnerClassDemo6 { public static void main(String[] args) { new Outer6().method(); } } class Outer6{ // 创建的匿名内部类相当于 // class Inner6 extends Object{ // public void show(){ // System.out.println("show run"); // } // } // new Inner6.show(); void method(){ new Object(){ public void show(){ System.out.println("show run"); } }.show(); } }
编译看左边
package java_demo_2; public class InnerClassDemo6 { public static void main(String[] args) { new Outer6().method(); } } class Outer6{ void method(){ Object obj = new Object(){ public void show(){ System.out.println("show run"); } }; obj.show(); // Error:(35, 13) java: 找不到符号 // 因为匿名内部类这个子类对象被向上转型为Object类型, // 这样就不再使用子类特有的方法了; } }