内容很多,很麻烦,静下心慢慢看
基本介绍
一个类的内部又完整的嵌套了另一个类结构,被嵌套的类称为内部类,嵌套其他类的类称为外部类
外部其他类:即其他类
特点:可以直接访问私有属性,并且可以体现类与类之间的包含关系
PS:底层源码中,有大量的内部类
基本语法
class Outer{
class Inner{
}
}
class Other{}
分类
- 定义在外部类局部位置上(如 方法内)
- 局部内部类 (有类名)
- 匿名内部类 (没有类名)(核心)
- 定义在外部类的成员位置上
3.成员内部类 (没用static修饰)
4.静态内部类 (使用static修饰)
1.局部内部类
①可以直接访问外部类的所有成员,包括私有
②不能添加访问修饰符(属于局部变量),只能用final修饰
③作用域:仅仅在定义它的方法或代码块中
④外部类在方法中,可以创建Inner的对象,然后调用方法
⑤外部其他类不能访问局部内部类 (局部内部类,本质是是一个局部变量)
⑥若外部类和局部内部类的成员重名时,默认遵循就近原则,即使用内部类的成员。若想访问外部类的成员,可以使用
Outer.this.Method();
代码
//演示局部内部类
public class LocalInerClass {
public static void main(String[] args) {
Outer01 outer01 = new Outer01();
outer01.m1();
// ⑤ Inner01 直接报错,外部类不能访问局部内部类
}
}
class Outer01{
private int n1 = 1;
private void m2(){
System.out.println("m2()");
}
public void m1(){
System.out.println("m1()");
//局部内部类是定义在外部类的局部位置,通常在方法中
//可以定义在方法中
// ② 只能用final,默认进行修饰,不能使用别的修饰符
final class Inner01{ //局部内部类 (本质还是一个类)
// ⑥ 若外部类和局部内部类的成员重名时,默认遵循就近原则
private int n1 = 2;
public void f1(){
// ① 可以直接访问外部类的所有成员,包括私有
System.out.println(n1);
// ⑥ 若想访问外部类的成员
System.out.println(Outer01.this.n1);
System.out.println(Outer01.this); // 本质是外部类的对象,即哪个对象调用m1,Outer01.this就是哪个对象,hashcode值
m2();
}
}
// ④ 外部类在创建的Inner01的方法内,调用Inner01的方法
Inner01 inner01 = new Inner01();
inner01.f1();
}
// ③ Inner01 inner01 = new Inner01();报错 只能在作用域中调用
// class Inner02{} 这个不能算局部内部类,只能算内部类
{
//也可以定义在代码块中
class Inner03{}
}
}
2.匿名内部类(重点)
实际上该类有名字,系统随机生成,但是被隐藏了,同时是一个对象
基本语法
new 类或接口(参数列表){
类体
};
需求:想使用A接口,并创建对象,且只是用一次
传统:写一个类,实现该接口,并创建对象,但不符合只使用一次的要求
故此使用匿名内部类
基于接口的匿名内部类
package chapter;
//演示匿名内部类
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer01 outer01 = new Outer01();
outer01.method();
}
}
class Outer01{
private int n1 = 1;
public void method(){
//基于接口的匿名内部类
//tiger编译类型 A接口, 运行类型 匿名内部类
//jdk底层在创建匿名内部类Outer01$1,立马创建实例,并把地址返回给tiger
//注意:匿名内部类只能使用一次,但创建的对象可以使用多次
A tiger =new A(){
public void cry(){
System.out.println("老虎叫");
}
};
tiger.cry();
tiger.cry();
}
}
interface A {
public void cry();
}
class Father{
public Father(String name){
}
public void test(){}
}
基于类的匿名内部类
package chapter;
//演示匿名内部类
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer01 outer01 = new Outer01();
outer01.method();
}
}
class Outer01{
private int n1 = 1;
public void method(){
//基于类的匿名内部类
//编译类型 Father 运行类型Outer01$2
/*
class Outer01$2 extends Father{}
*/
//同时也直接返回了匿名内部类Outer01$2的对象
//注意:("jack")参数列表会传递给 Father 构造器
Father father = new Father("jack"){
public void test(){
System.out.println("匿名内部类重写了test");
}
};
System.out.println(father.getClass());
father.test();
//基于抽象类的匿名内部类
Animal animal =new Animal(){
void eat(){
System.out.println("吃");
}
};
animal.eat();
}
}
interface A {
public void cry();
}
class Father{
public Father(String name){
}
public void test(){}
}
abstract class Animal{
abstract void eat();
}
注意
1.匿名内部类既是一个类的定义,本身又是一个对象,因此语法上看,有定义类的特征,有创建对象的特征,两种调用匿名内部类的方法
package chapter;
//演示匿名内部类
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer01 outer01 = new Outer01();
outer01.f1();
}
}
class Person{
public void hi(){
System.out.println("Person hi()");
}
public void ok(String name){
System.out.println("OK");
}
}
class Outer01{
private int n1 = 99;
public void f1(){
//第一种
Person person = new Person(){
@Override
public void hi() {
System.out.println("匿名内部类重写hi()");
}
};
person.hi(); //动态绑定,所以输出重写后的
person.ok("第一种调用 传参");
//第二种 直接调用
new Person(){
@Override
public void hi() {
System.out.println("哈哈哈");
}
}.hi();
//第二种的传参方法
new Person(){
@Override
public void hi() {
System.out.println("哈哈哈");
}
}.ok("jack");
}
}
2.可以访问外部类的所有成员(同局部内部类相同)
3.作用域:仅仅在定义它的代码块或者方法中(同上)
4.外部其他类不能访问匿名内部类(同上)
5.外部类和匿名内部类重名时,默认就近原则,可访问外部类成员(同上)
使用
1.当实参进行传递
package chapter;
public class AnonymousInnerClass {
public static void main(String[] args) {
CellPhone cellPhone = new CellPhone();
//1.传递的是实现了 Bell接口的匿名内部类 AnonymousInnerClass$1
//2.重写了ring()
//3.Bell bell = new Bell() {
// public void ring(){}
// }
cellPhone.alarm(new Bell() {
@Override
public void ring() {
System.out.println("懒猪起床");
}
});
cellPhone.alarm(new Bell() {
@Override
public void ring() {
System.out.println("小伙伴上课了");
}
});
}
}
interface Bell{
void ring();
}
class CellPhone{
public void alarm(Bell bell){
bell.ring();
}
}
3.成员内部类
定义在外部类的成员位置,没有static修饰
1.可以访问外部类的所有成员
2.可用修饰符(public protected 默认 private), 地位就是一个成员
3.作用域:与其他外部类的成员一样,为整个类体
4.可访问外部类的所有成员
5.外部类访问 成员内部类 :创建对象在访问
6.外部其他类 访问 成员内部类 (三种方式)
package chapter;
public class test {
public static void main(String[] args) {
//第一种
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
//第二种 外部类中编写一个方法,返回Inner的对象实例
Outer.Inner inner1 = outer.getInner();
//第三种
Outer.Inner inner2 = new Outer().new Inner();
}
}
class Outer{
class Inner{}
//第二种 所需的方法,用于返回Inner对象
public Inner getInner(){
return new Inner();
}
}
7.外部类,内部类成员同名,默认就近原则(同上)
4.静态内部类
定义在外部类的成员位置,用static修饰
1.直接访问外部类的所有成员,但不能直接访问非静态成员
2.可用任意访问修饰符修饰
3.作用域:整个类体
4.外部类访问 : 创建对象在访问
5.外部其他类 访问静态内部类
第一种,通过类名直接访问(满足访问权限)
Outer.Inner inner = new Outer.Inner();
inner.method();
第二种,编写一个方法,返回静态内部类的对象实例
public class test {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.getInner();
}
}
class Outer{
static class Inner{}
public Inner getInner(){
return new Inner();
}
}
6.内外部成员重名时,默认就近原则,若想访问外部类的成员,则可以使用(外部类名.成员)
!!!与上面略有不同,区别在于使用static修饰
测试
需改进,仅供参考
package chapter;
public class Test {
public static void main(String[] args) {
CellPhone p = new CellPhone();
p.testWork( new calcultor(){
@Override
public double work(double n1) {
return 0;
}
},1);
}
}
interface calcultor{
double work(double n1);
}
class CellPhone{
public void testWork(calcultor one,double n1){
double result = one.work(n1);
}
}