day01 - InnerClass

InnerClass

为什么使用内部类: 内部类是共享数据最简单的方式之一

内部类编译之后同样会生成.class文件.
其命名规则是: 外部类名字$内部类名字.class

class A {
    int i = 7;
    
    // 内部类
    class C {
        public void test() {
            System.out.prinln(i);
        }
    }
}

成员内部类

能够共享外部类的所有(静态 + 非静态)成员(属性 和 方法).

如何创建长远内部类的对象:

Outer.Inner in = new Outer().new Inner();
public class TestMemberInner {
    public static void main(String[] args) {
        /*
        内部类创建对象的方法:
        	(1) 外部类名.内部类名 变量名 = new 外部类名().new 内部类名()
        		Outer.Inner in1 = new Outer().new Inner();
        	(2) 先创建外部类的对象, 然后通过外部类的对象创建内部类对象.
        		Outer out = new Outer();
        		Outer.Inner in3 = out.new Inner();
        
        in1 和 in2使用的是不同的外部类对象创建的, 所以他们在访问外部类的变量时, 实际上调用的是不同对象的方法.
        
        对于外部类的方法, 从原理上来考虑, 一个类的所有对象, 调用的应该是同一个方法, 所以in1 和 in2调用的
        内部类的方法是相同的, 不过这个没有啥讨论的意义.
        
        但是对于静态成员变量, 这个应该是在类加载的时候声明的, 所以静态变量是属于类的, 而不属于某个对象.所以,
        in1 和 in2 如果调用的是外部类的静态变量, 那么他们调用的是同一个静态变量.
        
        而in3 和 in4用的是同一个外部对象创建的内部类对象.
        */
        Outer.Inner in1 = new Outer().new Inner();
        Outer.Inner in2 = new Outer().new Inner();
        Outer out = new Outer();
        Outer.Inner in3 = out.new Inner();
        Outer.Inner in4 = out.new Inner();
    }
}

class Outer { // 外部类
    int a = 3;			// 成员变量
    static int b = 5; 	// 静态变量
    
    class Inner {
        int x = 5;
        public void test() {
            /*
            对于a变量是否允许在内部类中调用:
            	test()是内部类的一个普通的方法,想要调用这个
            	方法就必须先实例化对象.要实例化Inner对象,就
            	必须实例化Outer对象,所以在调用这个方法的时候,
            	Outer对象已经存在, 并通过这个对象来实例化内
            	部类Inner.所以Outer类中的变量a是可以在内部类中
            	使用的.
            */
            System.out.println(a); // true
            System.out.println(b); // true
            System.out.println(x); // true
        }
    }
}

有的地方把static声明的变量称为静态变量, 有的地方也称为静态成员变量.就这次培训来说, 用的是静态变量

静态内部类

能够共享外部类的静态成员(属性 + 方法). 虽然这个类是静态的, 但是仍然可以创建对象.我认为静态内部类的static标记, 是说明: 这个类对外部类的访问能力只限于静态的成员

如何创建对象

Outer.Inner in = new Outer.Inner();

静态内部类能够共享的只有外部类的静态成员, 静态成员还需要用内部类共享吗?
不需要, 可以直接用类名访问, 那么静态内部类就不是为了共享成员的.
它的存在,是为了描述类和类的归属关系的.

public class TestStaticInner{
	public static void main(String[] args){
		Outer.Inner in1 = new Outer.Inner();
		Outer.Inner in2 = new Outer.Inner();
	}
}
class Outer{//蛤蜊壳 = 房东
	int a = 3;
	static int b = 5;

	static class Inner{//寄居蟹 = 房客
		int x = 7;
		static int y = 9;
		public void test(){
            //静态内部类的禁止访问外部类的非静态成员
			System.out.println(a);//false
			System.out.println(b);//true
            // 内部类的非静态方法当然可以访问类体的非静态成员
            // 但是内部类的静态方法不能访问内部类的非静态成员
			System.out.println(x);//true (取决于test()是否是非静态的)
			System.out.println(y);//true
		}
	}
}

局部内部类

局部就是在方法体的内部 或者 方法的参数, 比如局部变量

如果定义在静态方法中, 只能共享外部类的静态成员
如果定义在非静态方法中, 能够共享外部类的所有成员

局部内部类访问它所在方法中的局部变量必须是final

另外, 还有其所在的外部类的那个方法中的局部变量.只是JDK1.8之前, 必须手动加final, 8.0开始可以不加, 但是在编译阶段会自动加上.

根本原因: 因为局部内部类对象的生命周期比局部变量的生命周期长.当局部变量所处的函数执行积极而术后就已经死亡了, 不存在了, 但是局部内部类对象还可能一直存在(只要有人还引用该对象), 这样就会出现了一个悲剧的结果, 局部内部类对象访问一个已经不存在的局部变量.

解决办法: 用final修饰局部变量, 这是因为局部内部类最终会被编译为一个单独的类, 其所访问的final局部变量在编译时会成为这个类的属性(即在局部内部类中生成一个该局部变量的拷贝).通过将final局部变量复制一份, 复制品直接作为方法内部类中的数据成员, 由于被final修饰的变量赋值后不能在修改, 所以就保证了复制品与原始变量的一致.

public class TestLocalInner{
	public static void main(String[] args){

	}
}
class Outer{
	int a = 3;
	static int b = 5;
	public void gogo(int c){		//参数
		int d = 7;					//局部变量

		class Inner{				//局部内部类
			int x = 9;
			public void test(){
				System.out.println(a);//true (取决于gogo是否是非静态的)
				System.out.println(b);//true
				System.out.println(c);//true (取决于JDK版本 8.0开始就行)
				System.out.println(d);//true (取决于JDK版本 8.0开始就行)
				System.out.println(x);//true!!
			}
		}
		Inner in = new Inner();
		in.test();
	}
}

如何创建对象:

注意位置限定, 创建局部内部类的语句必须在类定义完成之后, 所在方法结束之前!

Inner in = new Inner();

匿名内部类

如果生个孩子 就是为了拿去卖钱的 就不需要给孩子起名字…
现实当中 很多时候 我们自己的名字根本不重要, 反而父母或者长辈的名字才重要…

局部内部类不但可以实现接口, 还可以继承父类.

// 用于实现接口
new 接口() {
    抽象方法的具体实现
}

// 用于继承父类
new 父类(传参) {
    抽象方法的具体实现
}
import java.util.*;
public class TestAnonyInner{
	public static void main(String[] args){
		Set<Integer> set = new TreeSet<>(new Comparator<Integer>(){
			@Override
			public int compare(Integer i1,Integer i2){
				return i2.compareTo(i1);
			}
		});
		Collections.addAll(set,55,33,44,11,22,22);
		//我要降序!
		System.out.println(set);

	}
}
/*
class X implements Comparator<Integer>{
	@Override
	public int compare(Integer i1,Integer i2){
		return i2.compareTo(i1);
	}
}
*/
// lamda表达式也可以将内部类在进行简化
import java.util.*;
public class TestAnonyInnerPlus{
	public static void main(String[] args){
		Set<Integer> set = new TreeSet<>((i1,i2) -> i2.compareTo(i1));
		Collections.addAll(set,55,33,44,11,22,22);
		//我要降序!
		System.out.println(set);

	}
}

匿名内部类能够共享外部类的那些成员?

取决于定义它的位置, 可能等价于上述三种的某一种:

定义在类体当中, 等价于成员内部类

定义在类体当中又有static修饰, 等价于静态内部类

定义在方法提当中, 等价于局部内部类

// 匿名内部类练习
public class TestAnonyInner2{
	public static void main(String[] args){
		//用普通写法 创建一个学生 作为Person的子类
		Student stu = new Student();
		stu.eat();
		//想要用匿名内部类的语法创建一个老师对象
		Person tea = new Person("孔子",2120){
			@Override
			public void eat(){
				System.out.println("老师吃仙贝");
			}
		};
		tea.eat();
	}
}
class Student extends Person{
	public Student(){
		super("子贡",2100);
	}
	@Override
	public void eat(){
		System.out.println("学生吃饺子");
	}
}
abstract class Person{
	String name;
	int age;
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	public abstract void eat();
}

共享数据的常用方式

一个凄美的爱情故事

​ 故事的主角是一对小情侣 一个小男孩和一个小女孩
​ 他们一起去看电影 然后买了两张电影票之后
​ 钱不太够了 于是只买了一杯大可乐
​ 但是呢 找服务员要了两根吸管 他们共享这一杯可乐…

​ 广寒宫 = 电影院
​ 貂蝉 = 可乐
​ 吕布 = 小男孩
​ 董卓 = 小女孩
​ test() = drink()

  1. 使用静态变量

    public class TestShareData1{
    	public static void main(String[] args){
    		吕布 lxb = new 吕布();
    		董卓 ddz = new 董卓();
    		lxb.test();
    		ddz.test();
    	}
    }
    class 广寒宫{
    	static Object 貂蝉 = new Object();
    }
    class 吕布{
    	public void test(){
    		System.out.println(广寒宫.貂蝉);
    	}
    }
    class 董卓{
    	public void test(){
    		System.out.println(广寒宫.貂蝉);
    	}
    }
    
  2. 使用参数传递(传参不要只会依赖构造方法, 要用setter)

    public class TestShareData2{
    	public static void main(String[] args){
    		Object 貂蝉 = new Object();
    
    		吕布 lxb = new 吕布(貂蝉);
    		董卓 ddz = new 董卓(貂蝉);
    		lxb.test();
    		ddz.test();
    	}
    }
    class 吕布{
    	Object 夫人;
    	public 吕布(Object 夫人){
    		this.夫人 = 夫人;
    	}
    	public void test(){
    		System.out.println(夫人);
    	}
    }
    class 董卓{
    	Object 夫人;
    	public 董卓(Object 夫人){
    		this.夫人 = 夫人;
    	}
    	public void test(){
    		System.out.println(夫人);
    	}
    }
    
  3. 使用内部类

    public class TestShareData3{
    	public static void main(String[] args){
    		广寒宫 g = new 广寒宫();
    		广寒宫.吕布 lxb = g.new 吕布();
    		广寒宫.董卓 ddz = g.new 董卓();
    		lxb.test();
    		ddz.test();
    	}
    }
    class 广寒宫{
    	Object 貂蝉 = new Object();
    	class 吕布{
    		public void test(){
    			System.out.println(貂蝉);
    		}
    	}
    	class 董卓{
    		public void test(){
    			System.out.println(貂蝉);
    		}
    	}
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值