目录
本知识点代码放在InnerClassTest02里面了
一、内部类概述
内部类innerClass就是类中的类,分为实例内部类,静态内部类,局部内部类三种,其中匿名内部类包括在局部内部类当中。研究这三种内部类主要是为了能够更好的利用变量,访问变量,给变量赋值……
二、实例内部类
实例内部类可以想象为实例变量,有以下几个特点:
1、实例内部类的创建必须是首先创建外部类对象,然后才能创建这个内部类对象。
2、实例内部类当中不能定义静态相关的变量和方法,当然可以定义实例相关的。疑问,为什么不能定义静态相关的呢???
三篇文章有解答:
https://blog.csdn.net/qq_36523667/article/details/79227944
https://blog.csdn.net/cdy1221/article/details/96309791
https://blog.csdn.net/sinat_31311947/article/details/58588704
当然看了之后还有疑问,就是虽然说这样是脱离了掌控,但是不是也是符合这个规矩的吗?它又没有创建对象,只是定义的时候进行了类的初始化。jvm在类加载的时候又不是创建这个对象,不是只是给初始化类和静态变量而已嘛,又没有创建对象,所以这个不应该是可以存在的吗???
3、实例内部类可以随便对外部类的实例变量和静态变量访问和赋值。
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
//外部类实例变量
String outVar = "xxxxx";
//外部类静态变量
static String static_outVar = "yyyyy";
//外部类实例方法
public void method01(){
Log.d(TAG, "method: 外部类实例方法执行");
}
//外部类静态方法
public static void method02(){
Log.d(TAG, "method02: 外部类静态方法执行");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ShiLiInnerClass shiLiInnerClass = new ShiLiInnerClass();
shiLiInnerClass.method03();
Intent intent = new Intent(this,MainActivity2.class);
startActivity(intent);
}
/*
* 总结:
* 实例内部类就是外部类的所有东西都可以用---->就把它当成一个实例的变量
* 成员变量,静态变量:都可以访问到而且可以赋值
* 成员方法,实例方法:都可以调用
* 自己也可以定义自己的实例相关的方法和变量
* 但是不能有静态相关的
*
* 然后注意,它是在外部类的基础上面的,有了这个外部类,才有这个实例类
*
* */
//实例内部类 相当于实例变量
public class ShiLiInnerClass{
//实例内部类不能有静态成员
//static String i;实例内部类不能有静态变量
//public static void method(){ } 实例内部类不能有静态方法
//可以有实例成员
//构造方法
//Inner classes cannot have static declarations
//static{ }
public ShiLiInnerClass() {
Log.d(TAG, "ShiLiInnerClass: 实例内部类构造方法执行");
}
//实例级别的变量
String i;
//实例级别的方法
public void method01(){
Log.d(TAG, "method01: 实例内部类的方法执行");
}
public void method02(){
//拿外部类的静态变量和成员变量
Log.d(TAG, "method02: 外部的成员变量:"+outVar+"外部的静态变量:"+static_outVar);
//给外部类的静态变量和成员变量赋值
outVar = "jjjjjjjjjjjj";
static_outVar = "ewwwwwwwwwwww";
Log.d(TAG, "method02: "+outVar+" :"+static_outVar);
}
public void method03(){
MainActivity.method02();
MainActivity.this.method01();
method02();
}
}
}
三、局部内部类
局部内部类可以想象为局部变量,分两种情况:一就是定义在方法里面的,二是定义在方法的参数里面的----->和局部变量一样,方法参数和方法里面定义的变量都是存储在方法区当中的,都是叫做局部变量的。局部内部类有以下特点:
1、局部内部类的对象只能在局部创建,出了局部就不能创建它的对象了。
2、局部变量(1方法参数中、2在方法中定义的变量)要是要传入到局部内部类当中必须使用final修饰,也就是说在局部内部类当中不能给这个局部变量在进行赋值了。至于具体为什么不行,这篇文章里面有讲解:
https://blog.csdn.net/qq_41864648/article/details/108214590
但是注意,虽然不能再次赋值,但是可以用来传递给其它变量赋值。
3、局部内部类当中可以随便访问外部类的成员变量(包括实例和成员变量)和为它们赋值。
四、匿名内部类
匿名内部类也是属于局部内部类当中的一种,遵循和局部内部类一样的特点,匿名内部类就是没有名字的类;比如我们有时候说的“new 接口”(接口是不能new的,我们会在{}中编写具体实现),大部分情况下我们就是要用到匿名内部类的。
//外部类
public class MainActivity2 extends AppCompatActivity {
String i;
static int x;
private static final String TAG = "MainActivity2";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
//new JubuInnerClass();局部内部类只能在局部创建对象,在外面是创建不了的
method01("http://www.baidu.com");
}
//局部内部类,想象成局部变量
/*
* 也就是在方法里面的内部类,这个内部类有一个特点就是传进去的局部变量只能是final修饰的,也就是不能在这个局部类给这些局部变量赋值了
* 但是外部类的成员变量和静态变量都是可以在里面赋值的
*
* 这个局部内部是在方法当中的,那么就是在某个外部类的方法当中的,所以也是依赖于这个外部类的。然后这个
* 内部类也是只能在这个方法里面创建,不能在其它地方创建的,所以其实它就是专属这个方法的内部类。
* */
//局部内部类
public void method01(String address){
//方法里面的类
String j = "jj" ; //这里的address和j都是存储在栈区当中的,都是属于局部变量的
class JuBuInnerClass{
public void JuBuInnerMethod(){
//Variable 'address' is accessed from within inner class, needs to be final or effectively final
//address = "http://www.baidu.com";
//Variable 'j' is accessed from within inner class, needs to be final or effectively final
//j = "jjjjjjj";
//以上说明局部变量到局部内部类当中必须是final修饰的,局部变量不能在局部内部类当中被赋值。
String j;//这里的j和外面的j是两个来的,所以可以共存,但是是很难区分的,一般不会这样命名。
//这里体现出外部类的成员变量和实例变量是可以访问和赋值的
//并且虽然局部变量是由final修饰的,但是是可以被传递到其它变量的,给其它变量赋值
i = "Hello";
x = 10;
// csdn文章解释:在JVM中,内部类不是直接调用方法的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部,
// 自己内部的方法调用的实际是自己的属性而不是外部类方法的参数。
// 因为内部类被编译的时候会生成一个单独的内部类的.class文件,这个文件并不与外部类在同一class文件中<<<<--------很重要
// 如果内部类掉了这些参数的值也不可能影响到原参数,然而这样却失去了参数的一致性,因为从编程人员的角度来看他们是同一个东西,
// 如果编程人员在程序设计的时候在内部类中改掉参数的值,但是外部调用的时候又发现值其实没有被改掉,<<<<------这句话是点睛之笔,和上面画箭头的挂钩
// 这就让人非常的难以理解和接受,为了避免这种尴尬的问题存在,
// 所以编译器设计人员把内部类能够使用的参数设定为必须是final来规避这种莫名其妙错误的存在
// 注意:以上说的也不定对,可能只是适用于局部内部类,不适用于实例内部类,因为实例内部类中的成员变量和静态变量是可以传入到里面并且进行赋值操作的
Log.d(TAG, "JuBuInnerClass: i:"+i+" x:"+x+" "+" address:"+address);
}
}
//在当前这个方法里面创建这个内部类
new JuBuInnerClass().JuBuInnerMethod();
}
//匿名内部类----匿名内部类其实就是局部内部类的一种
//这里也叫“new 接口”,但是实际上接口是不能new的,这里就是使用了匿名内部类,
// 匿名是这个接口是没有名字的
// 然后这个{}是接口方法的实现
//同样和局部内部类一样 外部类的实例和静态变量都是可以使用的
Thread thread = new Thread(new Runnable() {
String z;
@Override
public void run() {
i = "Hello";
x = 100;
z = "Hello";//这里的z不是局部变量,而是这个匿名内部类的实例变量,所以当然可以用,但是如果是局部变量就不能赋值了了!
}
});
}
五、静态内部类
静态内部类其实用的肯定是非常少的,因为实际上它就是和自己单独创建那个类一样了。所以它有以下的特点:
1、带个static
2、不能访问外部类中和实例相关的变量和方法。
六、共同特点
以上除了静态内部类,否则它们对应的外部类的实例变量(包括成员和静态变量)都是可以在内部类里面进行访问和赋值操作的。