面向对象通识19(内部类)
定义在类体中定义的类(包含内部类的类被称为外部类)
基本语法和外部类相同,区别:
- 可以使用以下三种修饰符
- 内部类可以用
static修饰,表明该内部类为外部类的一个实例 - 可以用
private修饰,表明该内部类只能在外部类中被访问 - 可以用
protected修饰,表名该内部类能在其外部类中被访问,也可以被其子类访问
- 内部类可以用
- 非静态内部类不能拥有静态成员
- 内部类可以直接访问外部类的私有成员,但
static内部类不能直接访问外部类的非static成员
意义
- 当某个类及其实例必须要依附于别的类的存在而存在,就需要定义该类的内部类(内部接口、内部枚举)
- 内部类可以提供更好的封装,可以通过
private修饰让它完全隐藏于外部类
特性
内部类可以直接访问外部private的成员变量
public class Cow {private double weight;public class CowLeg{public void test(){System.out.println("test方法");//直接访问外部类的private成员变量System.out.println("weight成员变量"+weight);}}}
内部类区分变量
举例:
public class Dog {private int len=20;private class DogTail{private int len=200;public void info(){System.out.println("len:"+len);}}static DogTail dt;public static void main(String[] args) {dt=new DogTail();//编译错误,static方法访问非static内部类}}
内部类可以直接访问外部类的成员变量,但如果内部类的方法、内部类的成员变量与外部类的成员变量重名时,就需要区分。
class Dog1{protected int len=2;}public class Dog extends Dog1{private int len=20;private class DogTail{private int len=200;public void info(){int len=2000;System.out.println("len:"+len);//就近访问局部变量System.out.println("len:"+this.len);//this.引用,限定访问当前类的实例变量System.out.println("len:"+Dog.this.len);//外部类.this.引用,限定访问当前类的外部类的实例变量System.out.println("len:"+Dog.super.len);//外部类.super.引用,限定访问当前类的外部类的父类的实例变量}}static DogTail dt;public void test(){//实例方法调用非静态内部类dt=new DogTail();dt.info();}public static void main(String[] args) {Dog d =new Dog();d.test();}}/*len:2000len:200len:20len:2*/
在外部类以外使用静态内部类
- 基本上使用内部类与试用版其他类没什么区别,唯一注意,
static成员不能使用非static内部类创建实例
(如果只是声明变量,不算主动使用)
- 在外部类以外使用静态内部类
该内部类一定不能用private修饰;- 声明变量:
外部类.静态内部类 变量名 - 创建对象:
new 外部类.静态内部类构造器 - 调用方法:
外部类.静态内部类. - 派生子类:
extands 外部类.静态内部类(注意构造器调用)
综上,把外部类名当做静态内部类的包名调用即可
- 声明变量:
举例:
public class StaticOuter {//定义内部类public static class Inner {private int age;public Inner(int age) {this.age = age;}public void inTest() {System.out.println("静态内部类的测试方法");}public static int sum(int a, int b) {return a + b;}@Overridepublic String toString() {return "Inner[age=" + this.age + "]";}}}
public class InnerTest {public static void main(String[] args) {StaticOuter.Inner nm=new StaticOuter.Inner(4);//声明变量、创建对象StaticOuter.Inner.sum(2,3);//调用方法nm.inTest();}}class Outer extends StaticOuter.Inner{//派生子类public Outer() {super(3);}}
在外部类使用非静态的内部类
- 内部类:也叫寄生类
static内部类的实例,要寄生在外部类本身之中- 只要用到该内部类,外部类就会被自动初始化
- 非
static内部类的实例,要寄生在外部类的实例之中
- 外部类:也叫宿主类
- 在外部类使用非静态的内部类:
- 声明变量:
外部类.静态内部类 变量名 - 创建对象:
宿主.new 费静态内部类构造器- 所谓宿主就是用外部类创建的对象名称
或者:new 外部类构造器.new 内部类构造器
第一个new的目的仅仅是为了得到宿主对象
- 所谓宿主就是用外部类创建的对象名称
- 访问类变量(只能是常量):
外部类.非静态内部类.类常量 - 派生子类:
extands 外部类.非静态内部类
重点在子类构造器第一行,必须用到的语法:宿主.super(参数)
- 声明变量:
非静态内部类(包括其子类)的实例的素质是外部类的实例,因此必须由开发者创建外部类实例作为宿主。
举例:
public class inClass {class B {public void test() {System.out.println("仅仅是一个非静态的内部类");}}
public class InnerTest {inClass.B in;inClass A=new inClass();//创建对象:宿主.new非静态内部类的构造器(参数);此处的A为宿主对象in=A.new B();//第一个new是主动创建一个宿主对象inClass.B iin=new inClass().new B();}class Outer1 extends inClass.B{public Outer1(){new inClass().super();}}
局部内部类
局部内部类放在方法中定义
局部内部类也只能用final修饰
(just like 局部变量)
public class LocalInner {public void a(){//局部内部类class In{}}public void b(){//局部内部类class In{}}}
局部内部类只能在所定义的方法中使用,局限性很强,所以用的很少
局部内部类的类文件名为外部类$N内部类.class
匿名内部类
(很常用,普遍存在于安卓开发)
匿名内部类是没有名字的类,只能在创建的时候立即创建实例,以后不能复用该类
语法:
new 父类构造器(参数)|接口(){//类体部分//一般的,类体部分就是实现抽象方法,因为没有类名,所以可以创建四大成员但是无法调用}
从上述语法可以看出:
- 匿名内部类必须要显示集成一个父类或者实现一个接口,不能同时实现多个接口。
- 不能实现父类的同时实现接口
- 匿名内部类不能是抽象类,因此必须实现抽象接口或是抽象父类中的所有抽象方法
- 可以定义出了构造器以外的四大成员,因为构造器的名字要和类名相同
举例:
public class 匿名内部类 {public static void main(String[] args) {animal an=new animal(2.3)//向上转型:此处用animal的子类的实例赋值{@Overridepublic void taste(){System.out.println("bad");}public void food(){System.out.println("为匿名内部类创建方法");}};//匿名内部类的类体an.taste();an.walk();//an编译时的类型是animal,不存在food方法Printable p=new Printable() {//类体部分只要实现抽象方法即可@Overridepublic void print() {System.out.println("打印数据");}@Overridepublic void inputDta() {System.out.println("输入数据");}};p.print();p.inputDta();}}abstract class animal{private double weight;animal(double weight){this.weight=weight;}public void walk(){System.out.println("Just walk.");}public abstract void taste();}interface Printable{//默认修饰符public和abstractvoid print();void inputDta();}
