面向对象通识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:2000
len:200
len:20
len: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;
}
@Override
public 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的子类的实例赋值
{
@Override
public void taste(){
System.out.println("bad");
}
public void food(){
System.out.println("为匿名内部类创建方法");
}
};//匿名内部类的类体
an.taste();
an.walk();
//an编译时的类型是animal,不存在food方法
Printable p=new Printable() {
//类体部分只要实现抽象方法即可
@Override
public void print() {
System.out.println("打印数据");
}
@Override
public 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和abstract
void print();
void inputDta();
}