内部类
将一个类放在另一个类内部,这个在其他类内部的类称为内部类, 或嵌套类。包含内部类的类称为外部类,或宿主类。
成员内部类分为两种:
静态内部类
非静态内部类
使用 static
修饰的内部类为 静态内部类。
一个Java源文件中定义多个类,不属于内部类。
//下面这两个不属于内部类
class A{}
public class B{}
非静态内部类
访问权限
外部类有默认和 public两种权限:默认为包, public为任何位置
内部类由4个访问权限:
private : 同一个类
默认: 同一个包
protected : 父子类
public类: 任何位置
访问变量
非静态内部类访问某个变量时:
先从方法内找是否存在该名字的局部变量,找到就使用,
如果找不到,就从内部类中查找是否存在该名字的成员变量, 找到就使用。
找不到就从所在的外部类找, 存在就是用。
找不到就出现编译错误。
外部内部成员可以使用 外部类名.this
获取,
内部类可以用 this.
获取
public class Outter {
private String str = "Outter str";
private class Inner{
private String str = "Inner str";
public void info(){
String str = "local str";
//访问外部
System.out.println(Outter.this.str);
//访问内部类
System.out.println(this.str);
//访问局部变量
System.out.println(str);
}
}
public void test(){
Inner inner = new Inner();
inner.info();
}
public static void main(String[] args){
new Outter().test();
}
}
//输出
Outter str
Inner str
local str
非静态内部类的成员可以访问外部类的 private 成员, 外部类的不能访问内部类的 private 成员。
外部类使用内部类的 private 成员时, 必须显式的创建内部类对象来调用。因为创建外部类对象时, 并不会创建内部类对象。
静态成员
静态成员不能访问非静态成员。
外部类的静态方法,静态代码块,不能访问非静态内部类。
非静态内部类不能有静态方法,静态成员变量,静态初始化块。
但可以有普通初始化块。
使用
调用内部类
Outter.Inner inner = new Outter().new Inner();
//或下面这样
Outter.Inner inner1;
Outter outter = new Outter();
inner = outter.new Inner();
创建子类:
创建子类时,必须保证子类构造器可以调用内部内构造器,调用时必须存在一个外部类对象。
class SubInner extends Outter.Inner{
public SubInner(Outter outter){
outter.super();
}
}
静态内部类
使用 static
修饰的内部类是静态内部类,属于外部类本身,不属于外部类的某个对象。
static
是把类的成员变成类相关, 而不是实例相关, 外部类的上一级程序单元是包, 所以不可使用 static 修饰外部类,但可以修饰内部类。
静态内部类的实例方法,不能访问外部类的实例变量,只能访问静态变量。
public class Outter {
private String str = "Outter str";
private static int b = 2;
static class StaticInner{
private static int a = 1;
private int c = 3;
public void test(){
//不能访问外部类的实例变量
// System.out.println(str);
System.out.println(b);
}
}
public void accessTest(){
//不能访问静态内部类成员
// System.out.println(c);
System.out.println(StaticInner.a);
System.out.println(new StaticInner().c);
}
}
接口
接口中允许定义内部类, 默认为 public static
修饰。
接口内部类只能是静态内部类。
静态内部类使用
调用时,无需创建外部类对象。
Outter.StaticInner inner2 = new Outter.StaticInner();
创建子类也比较简单
class SubStaticInner extends Outter.StaticInner{
}
局部内部类
放在方法里的类,称为局部内部类。
仅在方法内有效。
由于不能做方法以外调用, 所以局部内部类不能使用访问控制符和static
修饰符。
public static void main(String[] args){
class InnerClass{
int a;
}
class InnerSubClass extends InnerClass{
int b;
}
InnerSubClass innerSubClass = new InnerSubClass();
innerSubClass.a = 1;
innerSubClass.b = 2;
System.out.println(innerSubClass.a + innerSubClass.b);
}
//输出 3
实际开发中很少用到局部内部类。
匿名内部类
匿名内部类是继承一个父类,或实现一个接口。
匿名内部类不能是抽象类:当创建匿名内部类时,会立即创建对象
不能定义构造器: 因为没有类名,所以不能定义构造器。但是可以定义初始化块。
interface Product{
public String getName();
}
public class AnonymousTest {
public void info(Product p){
System.out.println("name is :" + p.getName());
}
public static void main(String[] args){
AnonymousTest at = new AnonymousTest();
at.info(new Product() {
@Override
public String getName() {
return "Milk";
}
});
}
}
//输出
name is :Milk
上面 info() 需要 Product 参数, Product 只是接口,不能创建对象,
因此定义一个匿名内部类实现Product接口。
定义匿名内部类,不需要 class
关键字。
匿名内部类必须实现它的抽象父类或接口里包含的所有抽象方法。
看下面的例子
abstract class Dev{
private String name;
public abstract int getPrice();
public Dev(){}
public Dev(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class AnonymousTest {
public void info(Product p){
System.out.println("name is :" + p.getName());
}
public void test(Dev d){
System.out.println("Dev name : " + d.getName() + " price: " + d.getPrice());
}
public static void main(String[] args){
AnonymousTest at = new AnonymousTest();
at.test(new Dev("M2") {
@Override
public int getPrice() {
return 50;
}
});
Dev d = new Dev() {
@Override
public int getPrice() {
return 100;
}
public String getName(){
return "M3";
}
};
at.test(d);
}
}
//输出
Dev name : M2 price: 50
Dev name : M3 price: 100
包含了有参和无参构造器,
实现了抽象类里的所有抽象方法, 还可以重写父类的普通方法。
局部变量
访问局部变量必须是 final
修饰的,
JAVA 8会自动加上 final.
这种称为 effectively final
。
public static void main(String[] args){
AnonymousTest at = new AnonymousTest();
int a = 8;
Dev d = new Dev() {
@Override
public int getPrice() {
//使用局部变量
System.out.println(a);
return 100;
}
public String getName(){
return "M3";
}
};
//不能重新赋值
// a = 3;
}
局部变量被匿名内部类使用后,不能修改值了,因为系统自动加上了final
修饰符。
地址: https://blog.csdn.net/yonggang7/article/details/86709708