1、内部类字面意思就是在一个类中定义的某个类。
内部类从名字上划分为有名内部类和匿名内部类。匿名内部类必须依赖于接口和抽象类创建,而有名内部类可以依赖于接口和抽象类创建,也可以不需要依赖于接口和抽象类创建。
创建一个接口,准备创建匿名内部类。
package test;
public interface OutInterface {
public void show();
}
创建匿名内部类和有名内部类,以及比较他们之间的区别。
package test;
public class Test{
public static void main(String[] args) {
//此处a假如要在内部类中使用,则在声明定义初始化之后则不能重新改变变量值,否则会报错。关于原因后面会有解释。此处我们可以通过调用方法给局部变量a动态的初始化。
String a = getStr("张三");
// a="aaa";由于a在内部类中使用,再次对a赋值,则内部类使用局部变量a处会报错。
//匿名内部类的定义 OutInterface为刚刚创建的接口名字
OutInterface out = new OutInterface() {
//匿名内部类成员变量
String b = "李四";
@Override
public void show() {
b="111";
System.out.println(a);
}
};
//匿名内部类的使用
out.show();//张三
// System.out.println(out.b); out.b 会报错。 有名内部类成员变量可以外部类使用,匿名内部类成员变量不可以被外部类访问。
//有名内部类的定义
class OutClass2 implements OutInterface{
//有名内部类成员变量
String b = "李四";
@Override
public void show() {
b="111";
System.out.println(a);
}
}
//有名内部类的使用
OutClass2 outClass2 = new OutClass2();
System.out.println(outClass2.b);//李四 有名内部类成员变量可以外部类使用,匿名内部类成员变量不可以被外部类访问。
outClass2.show();//张三
System.out.println(outClass2.b);//"111"
}
private static String getStr(String str){
if(str==null){
return "";
}
return str;
}
}
内部类从定义的位置又分为 和外部类方法同级定义的内部类、在外部类方法里面定义的内部类。
和外部类方法同级定义的内部类定义与使用。
package test;
public class Test{
String a = getStr("张三");
//和外部类方法同级定义的内部类
class OutClass1{
String b = "李四";
public void show() {
b="111";
System.out.println(a);
}
}
public static void main(String[] args) {
//和外部类方法同级定义的内部类的使用。
OutClass1 outClass1 = new Test().new OutClass1();
System.out.println(outClass1.b);//李四
outClass1.show();//张三
System.out.println(outClass1.b);//"111"
}
private static String getStr(String str){
if(str==null){
return "";
}
return str;
}
}
在外部类方法里面定义的内部类的定义与使用。
package test;
public class Test{
public static void main(String[] args) {
String a = getStr("张三");
//在外部类方法里面定义的内部类的定义
class OutClass2 implements OutInterface{
String b = "李四";
@Override
public void show() {
b="111";
System.out.println(a);
}
}
//在外部类方法里面定义的内部类的使用
OutClass2 outClass2 = new OutClass2();
System.out.println(outClass2.b);//李四
outClass2.show();//张三
System.out.println(outClass2.b);//"111"
}
private static String getStr(String str){
if(str==null){
return "";
}
return str;
}
}
2.关于外部类方法里定义的内部类要使用外部类方法里的局部变量时则该局部变量必须声明为final。局部变量的值不能改变的一些解释。
内部类里面使用外部类的局部变量时,其实就是内部类的对象在使用它,内部类对象生命周期中都可能调用它,而内部类试图访问外部方法中的局部变量时,外部方法的局部变量很可能已经不存在了,那么就得延续其生命,拷贝到内部类中,而拷贝会带来不一致性,从而需要使用final声明保证一致性。
说白了,内部类会自动拷贝外部变量的引用,为了避免:1. 外部方法修改引用,而导致内部类得到的引用值不一致 2.内部类修改引用,而导致外部方法的参数值在修改前和修改后不一致。于是就用 final 来让该引用不可改变。
内部类回调里访问position的时候createAnimatorView()早就执行完了,position如果不是final的,回调的时候肯定就无法拿到它的值了,因为局部变量在函数执行完了以后就被回收了。
我们反编译看一下,首先定义接口和匿名内部类:可以看到名为number的局部变量是作为构造方法的参数传入匿名内部类的。
如果Java允许匿名内部类访问非final的局部变量的话,那我们就可以在TryUsingAnonymousClass$1中修改paramInteger,但是这不会对number的值有影响,因为它们是不同的reference。
这就会造成数据不同步的问题。