1 this$0是什么意思
public class Outer {//this$0
public class FirstInner {//this$1
public class SecondInner {//this$2
public class ThirdInner {
}
}
}
}
说一个场景:当我们拿到了一个内部类的对象Inner,但是又想获取其对应的外部类Outer,那么就可以通过this$0来获取。this$0就是内部类所自动保留的一个指向所在外部类的引用。
//通过工具获取到Inner实例对象
Outer.Inner inner = getInner();
//获取内部类Inner的一个字段this$0信息
//this$0特指该内部类所在的外部类的引用,不需要手动定义,编译时自动加上
Filed outerField = inner.getClass().getDeclaredField("this$0");
//this$0是私有的,提升访问权限
outerField.setAccessible(true);
//拿到该字段上的实例值
Outer outer = (Outer)outerField.get(inner);
3. ,外部类中的内部类编译后会产生一个 外部类类名$内部类类名.calss的文件
注意:Class.forName()中的类名不能使用eclipse中的Copy qualified Name 来获取,应为内部类编译后会产生两个文件,具体做法是:到工程的根目录下,找到bin文件夹,java文件编译后的calss文件都放在这个目录下,找到编译后的内部类的class文件,复制类名,然后在前面加上包名即可
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
try {
Class clazz=Class.forName("reflect.OuterClass$InnerClass");
Constructor[] constructors = clazz.getDeclaredConstructors();
for(Constructor c:constructors){
System.out.println(c);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
4 forNam的用法
Class.forName("")返回的是类
Class.forName("").newInstance()返回的是object
Class.forName("");的作用是要求JVM查找并加载指定的类,
newInstance: 弱类型。低效率。只能调用无参构造。
new: 强类型。相对高效。能调用任何public构造。
使用newInstance()方法的时候,就必须保证:1、这个 类已经加载;2、这个类已经连接了。
5 基础知识:
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。下面就先来了解一下这四种内部类的用法。
成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量
外部类.this.成员方法
1成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。
内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。比如上面的例子,如果成员内部类Inner用private修饰,则只能在外部类的内部访问,如果用public修饰,则任何地方都能访问;如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。这一点和外部类有一点不一样,外部类只能被public和包访问两种权限修饰。
class Circle {
private Draw getDrawInstance() {
return new Draw();
}
class Draw { //内部类
}
}
2 局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
public People getWoman(){
class Woman extends People{ //局部内部类
int age =0;
}
return new Woman();
}
注意,局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。
3 匿名内部类应该是平时我们编写代码时用得最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。
scan_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
}
});
4 静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,
这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法
class Outter {
static class Inner {
}
}
}
深入理解:
1.为什么成员内部类可以无条件访问外部类的成员
编译器在进行编译的时候,会将成员内部类单独编译成一个字节码文件。
也就是说编译器会默认为成员内部类添加了一个指向外部类对象的引用
final com.cxh.test2.Outter this$0;
虽然我们在定义的内部类的构造器是无参构造器,编译器还是会默认添加一个参数,该参数的类型为指向外部类对象的一个引用,所以成员内部类中的Outter this&0 指针便指向了外部类对象,因此可以在成员内部类中随意访问外部类的成员。从这里也间接说明了成员内部类是依赖于外部类的,如果没有创建外部类的对象,则无法对Outter this&0引用进行初始化赋值
public com.cxh.test2.Outter$Inner(com.cxh.test2.Outter);
2 为什么局部内部类和匿名内部类只能访问局部final变量
局部变量的值在编译期间就可以确定,则直接在匿名内部里面创建一个拷贝。如果局部变量的值无法在编译期间确定,则通过构造器传参的方式来对拷贝进行初始化赋值。
为了使数据一致性,java编译器就限定必须将变量a限制为final变量,不允许对变量a进行更改(对于引用类型的变量,是不允许指向新的对象)
3 静态内部类有特殊的地方
静态内部类是不依赖于外部类的,也就说可以在不创建外部类对象的情况下创建内部类的对象。另外,静态内部类是不持有指向外部类对象的引用的,这个读者可以自己尝试反编译class文件看
java中内部类使用场景:
1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整,
2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
3.方便编写事件驱动程序
4.方便编写线程代码
创建
创建静态内部类对象的一般形式为: 外部类类名.内部类类名 xxx = new 外部类类名.内部类类名()
创建成员内部类对象的一般形式为: 外部类类名.内部类类名 xxx = 外部类对象名.new 内部类类名()
关于成员内部类的继承问题。一般来说,内部类是很少用来作为继承用的。但是当用来继承的话,要注意两点:
(1)成员内部类的引用方式必须为 Outter.Inner.
(2)构造器中必须有指向外部类对象的引用,并通过这个引用调用super()。这段代码摘自《Java编程思想》
public class Test {
public static void main(String[] args) {
Outter outter = new Outter();
outter.new Inner().print();
}
}
class Outter
{
private int a = 1;
class Inner {
private int a = 2;
public void print() {
int a = 3;
System.out.println("局部变量:" + a);
System.out.println("内部类变量:" + this.a);
System.out.println("外部类变量:" + Outter.this.a);
}
}
}
参考资料:
https://blog.csdn.net/qq_33371372/article/details/82467049
https://www.cnblogs.com/dolphin0520/p/3811445.html