java基础部分学习:8、内部类

1、内部类

1、定义:一个类的内部又完整的嵌套了另一个类结构,被嵌套的类称为内部类(inner class)。
内部类是我们类的第五大成员(属性、方法、构造器、代码快、内部类)。
内部类最大特点就是:可以直接访问私有属性。

class Outer {
	class Inner{}  // 内部类
}
class Other {} // 外部其它类
1.1、内部类分类

1、定义在外部类局部外置上(比如方法内):
a、局部内部类(有类名)
b、匿名内部类(无类名!!!!)
2、定义在外部类的成员位置上:
a、成员内部类(没有static修饰)
b、静态内部类(有static修饰)

1.1.1、局部内部类:

总结:

1、局部内部类定义在外部类局部位置,通常在方法
2、局部内部类可以直接访问外部类成员
3、局部内部类不能添加访问修饰符,但是可以使用final修饰,以防被继承
4、局部内部类作用域:仅仅在定义他的方法或者代码块中(内部类可以写在代码快中)
5、外部类可以在方法中,创建内部类对象,然后调用内部类方法
6、外部其它类不能访问局部内部类,因为局部内部类类似于局部变量。
7、如果外部类和局部内部类成员重名时,默认遵循就近原则,如果想要访问外部类成员,可以使用(外部类名.this.成员)去访问。

public static void main(String[] args) {
	Outer outer = new Outer();
	outer.m1();
}

class Outer {
	private int n1 = 100;
	private int n3 = 200;
	private void m2() {
		System.out.println("outer方法m2()");
	}
	public void m1() {  // 外部类方法
	// 3、局部内部类不能添加访问修饰符,但是可以使用final修饰,以防被继承
	// 4、局部内部类作用域:仅仅在定义他的方法或者代码块中(内部类可以写在代码快中)
		final class Inner {  // 1、局部内部类定义在外部类局部位置,通常在方法
			private int n1 = 888;
			public void f1() {
				System.out.println("n3=" + n3); // 2、局部内部类可以直接访问外部类成员				  				
				m2();
				System.out.println("n1=" + n1);  // 888
				System.out.println("外部类的n1=" + outer.this.n1);
			}
		}
		// 5、外部类可以在方法中,创建内部类对象,然后调用内部类方法
		Inner inner = new Inner();
		inner.f1();
	}
}

1.1.2、匿名内部类:

1、本质还是一个类。
2、是一个内部类:定义在外部类的局部位置:如方法中
3、该类没有名字。
4、同时还是一个对象。

// 基本语法
new 类名/接口名(参数列表) {
	类体
}
基于接口的匿名内部类:
1、为什么需要基于接口的匿名内部类呢?

对于一些实现接口的类我们只是使用一次,但是创建类又比较麻烦,因此为了简化开发,可以使用匿名内部类。

2、在使用匿名内部类的时候发生了什么?

匿名内部类其实也有名字,只是我们看不见而已,是jdk帮我们创建的:以外部类名+$符号+数字构成

它是使用匿名类帮我们实现了接口,并将匿名类给实例化了。

public static void main(String[] args) { 
	Outer outer = new Outer();
	outer.method();
}

class Outer {
	private int n1 = 10;
	public void method() {
	// tiger的编译类型是:IA,编译看左边
	// tiger的运行类型是:匿名内部类: Outer$1(名字是外部类名字+$符号)
	/*
		new IA()做了什么事情呢?
		 jdk底层是创建了一个类Outer$1实现了接口IA并将该类给实例化,并将该类对象地址返回给了tiger
		 匿名内部类只能使用一次就不能再次使用
		class Outer$1 implements IA { 	
			@Override
			public void cry() {
				System.out.println("老虎叫");
			}
		}
	*/
		IA tiger = new IA() {   // 使用匿名内部类
			// @Override
			public void cry() {
				System.out.println("老虎叫");
			}
		};
		tiger.cay();
	}
}

interface IA {
	public void cry();
}

// 传统方法实现接口:需要再创建一个类,并创建对象来实现。
// 但是如果这些类都只是使用一次,这样创建类过于麻烦,为了简化开发,可以使用匿名内部类:
class Tiger implements IA {
	// @Override
	public void cry() {
		System.out.println("老虎叫");
	}
}
public static void main(String[] args) {
	Cellphone cellphone = new Cellphone();
	// 调用方法时:直接传入一个实现了ICaluate接口的匿名内部类,改匿名内部类可以灵活的实现work方法,完成不同的计算任务。
	/*
	ICaluate iCaluate = new ICalculate() {   // 编译类型:ICaluate 运行类型:匿名内部类
		@Override
		public double work(double n1, double n2) {
			retruen n1 + n2;
		}
	}
	*/
	cellphone.testWork(new ICalculate() {
		@Override
		public double work(double n1, double n2) {
			retruen n1 + n2;
		}
	}, 10, 20)
}

interface ICalculate {
	public double work(double n1, double n2);
}

class CellPhone {
	public void testWork(ICaluate iCaluate, double n1, double n2) {
		double result = iCaluate.work(n1, n2);
		System.out.println("计算后的结果是:" + result);
	}
}
总结:

IA接口里面有一个方法,可以不写方法体;有一个普通类normalClass,里面有一个方法AchieveIa用来实现(调用)接口方法,因此该普通类方法的参数要是接口(IA ia),也可以传入别的参数;主方法main中创建普通类normalClass 的实例对象(new一下),用该实例对象调用自己类的AchieveIa方法,但是该方法传入的参数是重写了接口方法的匿名内部类。

基于类的匿名内部类:就是底层创建匿名类继承类。
class Outer {
	public void method() {
	/*
		class Outer$2 extends Father {
				@Override
				public void test() {
				System.out.println("匿名内部类");
			}
		}
	*/
	// father 编译类型为:Father
	// father运行类型为:Outer$2
		Father father = new Father() {
			@Override
			public void test() {
			System.out.println("匿名内部类的test方法");
			}
		};
		/*
			运行看右边:因为匿名类重写了father方法,所以输出的是匿名类的值。
			没有重写就是找父类的值。
		*/
		father.test();  // 输出:匿名内部类的test方法
		
		Animal animal = new Animal() {
			@Override
			public void eat() {
			System.out.println("动物吃骨头);
			}
		};
		animal.eat();  // 输出:动物吃骨头
	}
}


class Father {   // 普通类
	public Father(String name) {
		System.out.println("father");
	}
}

abstract class Animal {  // 抽象类
	public void eat();
}

匿名内部类细节:

1、匿名内部类可以调用匿名内部类的方法:
在这里插入图片描述

class Outer {
	public void method() {
		Father father = new Father() {
			@Override
			public void test() {
			System.out.println("匿名内部类的test方法");
			}
		};
		father.test();  // 输出:匿名内部类的test方法

		new Father() {
			@Override
			public void test() {
				System.out.println("匿名内部类的test方法");
			}
			@Override
			public void ok(String str) {
				super.ok(str);  // super调的还是父类Father. 因为匿名类继承了father
			}
		}.test("jack");    // 支持直接调用方法。因为匿名内部类本身也是返回对象

	}
}


class Father {   // 普通类
	public Father(String name) {
		System.out.println("father");
	}
	public void test() {}
	public void ok(String str) {
		System.out.println(str);
	}
}

2、可以直接访问外部类的所有成员,包括私有的。

3、不能添加访问修饰符,因为他就相当于一个局部变量。

4、作用域:仅仅在定义他的方法或者代码快中。

5、外部其它类不能访问局部内部类,因为局部内部类类似于局部变量。

6、如果外部类和局部内部类成员重名时,默认遵循就近原则,如果想要访问外部类成员,可以使用(外部类名.this.成员)去访问。

3、匿名内部类的最佳实践:

当作实参直接传递,简洁高效。
public static void main(String[] args) { 
// 将内部类当作实参直接传递:
	f1(new IA() {
		@Override
		public void show() {
			System.out.println("hello word");
		}
	});

	// 传统方法
	f1(new Say());
	
	public static void f1(IA ia) {  // 该方法形参是接口类型
		ia.show();   // 通过形参调用接口方法
	}
}

interface IA {
	void show();
}

// 传统方法
class Say implements IA {
	@Override
	public void show() {
		System.out.println("hello word");
	}
}

巩固练习:

题目要求;
一个bell接口,里面有一个ring方法,一个CellPhone 类,里面有一个alarmClock方法。使用匿名内部类为实参的方法打印:该起床了、该上课了。

public static void main(String[] args) { 
	CellPhone cellphone = new CellPhon();
	// 1、alarmClock方法传递的参数是:实现了Bell接口的匿名内部类
	// 2、该类重写了ring方法。
	// 3、改匿名内部类传递给了 Bell bell
	cellphone.alarmClock(new Bell() {
		@Override
		public void ring() {
			System.out.println("该起床了。");
		}
	});
	
		cellphone.alarmClock(new Bell() {
		@Override
		public void ring() {
			System.out.println("改上课了。");
		}
	});
}

interface Bell {
	void ring();
}

class CellPhone {
/* 4、Bell bell = new Bell() {   编译类型是Bell,运行类型是匿名内部类
		@Override
		public void ring() {
			System.out.println("该起床了。");
		}
*/
	public void alarmClock(Bell bell) {  // 以接口为方法参数
		bell.ring();   // 调用ring方法。
	}
}

3、成员内部类:定义在外部类的成员位置

1、作用域:和外部成员其他类一样,为整个外部类体。

2、外部类访问内部类:创建对象再去访问。

class Outer {
	private int n1 = 10;
	public String name = "lisi";
	
	class Inner01 {  // 地位和外部类成员一样
		public void say() {
			System.out.pritln("hello word");
			System.out.pritln(n1);   // 可以使用外部类所有成员,包括私有
		}
	}

	public void f1() {
		Inner01 inner01 = new Inner01();   // 使用内部类
		inner01.say();
	}
}

3、外部其他类,如何访问成员内部类:

public static void main(String[] args) {
	Outer.Inner inner = Outer.new Inner();
}

class Outer {
	class Inner {
	}
}

4、静态内部类:放在外部类的成员位置

1、使用static修饰。

2、可以直接访问外部类的所有静态成员,不能直接访问非静态成员。

3、可以添加任意访问修饰符。

class Outer {
	private int n1 = 10;
	public String name = "loso";

	static class Inner {
		public void say() {
			System.out.println(name);
		}
	}
	public void m1() {
		Inner inner = new Inner();
		inner.say();
	}
}

4、外部其他类使用静态内部类:

class Other {
	Outer.Inner inner = new Outer.Inner();  // 因为是静态内部类,可以通过外部类名直接访问(但是要满足访问权限)
}
class Outer {
	static class Inner {]
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值