内部类
一个类或者接口定义在另外一个类后后者接口的内部
将一个类定义置入另一个类定义中,这就叫做“内部类”
- 内部类之外的类称为外部类
- 内部类的名称必须区别与它所在的外部类,和其他类之间没有要求
- 内部类可以访问其外部类的所有变量和方法
- 外部类不能直接访问内部类的实现细节
- 内部类比外部类多了private/protected/static三个修饰符,这三个修饰符不能用在外部类上
- 非静态内部类不能拥有静态成员
package com.yan4;
public class Test1 {
}
class A1 {
// class A1{} 内部类的名称不允许和外部类名称相同
public class B1 {// 内部类的范围限定词可以使用4种不同的范围限定;外部类只能使用public或默认
public void pp() {
System.out.println(name);// 内部类可以访问其外部类的所有变量和方法
}
private int num;
// 非静态内部类不能拥有静态成员
// private static int age;
}
private static class C1 {
private static int age;
public void pp() {
System.out.println(name);
}
}
private static String name;
public void aa() {
// 外部类不能直接访问内部类的实现细节
// System.out.println(num);
B1 bb = new B1();
System.out.println(bb.num);
}
}
内部类的作用
内部类提供更好的封装
内部类可以直接访问外部类的私有成员外部类不能直接访问内部类的成员,需要构建内部类对象才能访问匿名内部类适合用于创建仅仅使用一次使用的类
内部类相关的设计
- 分析事物时发现该事物描述还有事物,而且这个事物还在访问被描述事物的内容
例如牛和牛腿如果一个事物离开另外一个事物后则没有任何意义,这种情况下建议使用内部类,不允许其他类访问
- 内部类能直接访问外部类中成员,是因为内部类持有了外部类的引用,即外部类名.this
内部类分类
在 Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。内部类实际拥有外部类的一个引用,在构造函数中将外部类的引用传递进来。
非静态内部类
基础语法
public class A1{protected class B1{}//静态内部类是protected static class B1{}}
非静态内部类的特点:
1、和其他类一样,它只是定义在外部类中的另一个完整的类结构
- 可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关
- 可以在非静态内部类中声明属性、方法、构造器等结构,但是不允许声明静态成员,但是可以继承父类的静态成员,而且可以声明静态常量。
- 可以使用abstract修饰,因此它也可以被其他类继承
- 可以使用final修饰,表示不能被继承
- 编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名和$符号。
2、和外部类不同的是,它可以允许四种权限修饰符:public,protected,缺省,private外部类只允许public或缺省的3、还可以在非静态内部类中使用外部类的所有成员,哪怕是私有的4、在外部类的静态成员中不可以使用非静态内部类哦就如同静态方法中不能访问本类的非静态成员变量和非静态方法一样5、在外部类的外面必须通过外部类的对象才能创建非静态内部类的对象因此在非静态内部类的方法中有两个this对象,一个是外部类的this对象,一个是内部类的this对象
访问方法:直接访问外部类中内部类中的成员
class B1 {private String pwd;private void dd(){}protected class C1 {private String name;private void pp(){System.out.println(pwd);//内部类可以直接访问外部类中的私有成员//另外的写法 B1.this.pwddd();//另外的写法 B1.this.dd();}}public void ee(){//如果需要访问内部类中的成员,则必须首先创建内部类对象C1 cc=new C1();//通过构建的内部类对象则可以访问内部类中的私有成员cc.name="abc";cc.pp();}}
外部类.内部类 in=new 外部类().new 内部类();
public class A1 {public static void main(String[] args) {B1 b = new B1();B1.C1 cc=b.new C1();//内部类是否可以访问到,取决于内部类上的范围限定词}}class B1 {class C1{}}
静态内部类
基础语法
public class A1{public static class B1{}//静态内部类}
静态内部类的特点:
和其他类一样,它只是定义在外部类中的另一个完整的类结构
- 可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关
- 可以在静态内部类中声明属性、方法、构造器等结构,包括静态成员
- 可以使用abstract修饰,因此它也可以被其他类继承
- 可以使用final修饰,表示不能被继承
- 编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名和$符号。
和外部类不同的是,它可以允许四种权限修饰符:public,protected,缺省,private外部类只允许public或缺省的只可以在静态内部类中使用外部类的静态成员在静态内部类中不能使用外部类的非静态成员哦在外部类的外面不需要通过外部类的对象就可以创建静态内部类的对象如果在内部类中有变量与外部类的静态成员变量同名,可以使用“外部类名."进行区别
静态内部类中,也可以有非静态数据、非静态方法或者又一个非静态内部类
静态内部类中,不能访问外部类的非静态成员,这是由Java语法中【静态方法不能直接访问非静态
成员】所限定
局部内部类
可以将内部类定义在一个方法或者一个代码块内
public class A1 {private int age = 123;public static void main(String[] args) {A1 aa = new A1();}public void pp() {Date birth = new Date();// B1 bb=new B1();语法错误,要求局部内部类必须先定义后使用class B1 { // 局部内部类,只能在所在的{}范围中使用,具备内部类的范围限定词和临时变量一致,只能添加final或者abstractpublic void ff() {System.out.println(age);A1.this.age = 555;// 可以直接访问外部类中的成员System.out.println(birth);// 语法报错,在局部内部类中使用外部的临时变量,则外部临时变量必须是final的,只是final可以省略// birth = new Date();针对引用类型修改地址是不允许,但是可以修改属性System.out.println("B1...ff()");}}B1 bb = new B1();}}
局部内部类的特点:
1、和外部类一样,它只是定义在外部类的某个方法中的另一个完整的类结构
- 可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关
- 可以在局部内部类中声明属性、方法、构造器等结构,但不包括静态成员,除非是从父类继承的或静态常量
- 可以使用abstract修饰,因此它也可以被同一个方法的在它后面的其他内部类继承
- 可以使用final修饰,表示不能被继承
- 编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名、$符号、编号。
这里有编号是因为同一个外部类中,不同的方法中存在相同名称的局部内部类2、和成员内部类不同的是,它前面不能有权限修饰符等3、局部内部类如同局部变量一样,有作用域4、局部内部类中是否能访问外部类的静态还是非静态的成员,取决于所在的方法5、局部内部类中还可以使用所在方法的局部常量,即用final声明的局部变量JDK1.8之后,如果某个局部变量在局部内部类中被使用了,自动加final
匿名内部类
匿名内部类就是内部类的简写格式
public class A1{public void pp(){class B1 extends C1{}}}//简化写法public class A1{public void pp(){new C1(){};//原始命名类的写法class B1 extends C1{} new B1();}}
匿名内部类的前提是必须继承或者实现一个外部类或者接口
匿名内部类由于没有名字,所以它没有构造函数如果这个匿名内部类继承了一个只含有带参数构造函数的父类,创建它的时候必须带上这些参数不能定义静态成员
匿名内部类的使用场景
当方法参数是接口类型时,而且接口中的方法不超过三个,可以用匿名内部类作为实际参数进行传递
匿名内部类的使用限制
匿名内部类不能是抽象的匿名内部类不能定义构造器,默认和父类相似的构造器JDK1.8-要求给局部内部类、匿名内部类访问的局部变量必须使用final修饰,从JDK1.8开始这个现实被取消了,但是默认是final的(不能修改)
package com.yan1;
public class Test3 {
public static void pp(IA3 a) {
System.out.println("Test1...pp.begin");
a.pp();
System.out.println("Test1...pp.end");
}
public static void main(String[] args) {
// 匿名内部类第一种写法
// pp(() -> {
// System.out.println("Lambda");
// });
// 匿名内部类第二种写法
// pp(() -> System.out.println("Lambda"));
// 匿名内部类第三种写法
// IA3 aa = new IA3() {
// @Override
// public void pp() {
// System.out.println("Lambda");
// }
// };
// pp(aa);
// 匿名内部类第四种写法
pp(new IA3() {
@Override
public void pp() {
System.out.println("Lambda");
}
});
}
}
@FunctionalInterface
interface IA3 {
public void pp();
}