内部类详解

内部类顾名思义就是定义在其他类内部的类。其作用主要有如下几点:

1.内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其它类访问该类。

2.内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员(局部内部类和匿名内部类不是类成员),同一个类的成员之间可以相互访问。但外部类不能访问内部类的实现细节,例如内部类的成员变量。

3.匿名内部类适合用于创建那些仅需要一次使用的类。

内部类与普通类的有两个区别:

1.内部类比外部类可以多使用三个修饰符:private,protect,static---外部类不可以使用这三个修饰符。

注意:static不能修饰局部内部类(局部内部类是定义在方法里的类),这是因为局部内部类的上一级程序为方法,其作用域也就是所在的方法,相当于局部成员,其他程序永远无法访问到。

2.非静态内部类不能拥有静态成员。

非静态内部类和静态内部类统称为成员内部类。使用static修饰的成员内部类是静态内部类,没有使用static修饰的成员内部类事非静态内部类。

非静态内部类里可以直接访问外部内的私有数据,这是由于在非静态内部类对象里,保存了一个它所寄生的外部类对象的引用(当调用非静态内部类的实例方法时,必须有一个非静态内部类实例,非静态内部类实例必须寄生在外部类实例里)。

在非静态内部类的方法内访问某个变量时,系统优先在该方法内查找是否存在该名字的局部变量,如果没有找到,则向上一级查找,即该方法所在的内部类,如果没有,则再向内部类所在的类成员变量查找。

注意:如果外部类成员变量、内部类成员变量与内部类里方法的局域变量同名,则可以通过使用this、外部类类名.this作为限定来区分。

非静态内部类的成员可以访问外部类的private成员,但是反过来则不成立。因为非静态内部类的成员只在非静态内部类范围类是可知的,并不能被外部内直接使用。如果外部内需要访问非静态内部类的成员,则必须显式创建非静态内部类对象来调用访问其实例成员。示例代码如下:

public class InnerClassTest {

privateint outerNum=2;

class InnerClass{

privateint innerNum=6;

publicint innerPubNum=8;

public void accessOuterNum(){

//非静态内部类直接访问外部类的成员变量

System.out.println("访问外部类的outerNum的值:"+outerNum);

}

}

public void accessInnerNum(){

//下面两行都将报错

//System.out.println("访问内部类的innerNum的值:"+innerNum);

//System.out.println("访问内部类的innerNum的值:"+innerPubNum);

//创建显式非静态内部类对象,然后再调用

System.out.println("访问内部类的innerNum的值:"+new InnerClass().innerNum);

System.out.println("访问内部类的innerNum的值:"+new InnerClass().innerPubNum);

}

public static void main(String[] args) {

InnerClassTest innerClassTest=new InnerClassTest();

// 如果外部类能访问非静态类的实例成员,accessInnerNum(){System.out.println("访问内部类的innerNum的值:"+innerNum);}

//此时非静态内部类还不存在,所以就会引发错误

innerClassTest.accessInnerNum();


}

}

静态内部类:如果使用static来修饰一个内部类,则这个内部类就属于外部类本身,而不属于外部类的某个对象。因此,使用static修饰的内部类被称为类内部类,也称静态内部类。相当于外部类的一个静态成员。同时,静态内部类可以包含静态成员,也可以包含非静态成员。根据静态成员不能访问非静态成员的规则,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。示例代码如下:

public class StaticInnerClassTest {

privateint outerNum=1;

privatestatic int outerStaticNum=2;

static class StaticInnerClass{

privatestatic int age;

public void accessOuterNum(){

//注释代码报错,因为静态内部类无法访问外部类的实例变量。

//System.out.println(outerNum);

System.out.println(outerStaticNum);

}

}

}

注意:外部类依然不能直接访问静态内部类的成员,但可以使用静态内部类的类名作为调用者来访问静态内部类的类成员,也可以使用静态内部类对象作为调用者来访问静态内部类的实例成员。示例代码如下:

public class StaticInnerClassTest {

privateint outerNum=1;

privatestatic int outerStaticNum=2;

static class StaticInnerClass{

privatestatic int age;

privateint age2=1;

}

public void accessOuterNum(){

//相当于类静态成员变量的调用

System.out.println(StaticInnerClass.age);

//相当于显式创建类对象来访问其实例成员

System.out.println(new StaticInnerClass().age2);

}

public static void main(String args[]){

//与acessOuterNum方法中的调用方法一致

System.out.println(StaticInnerClassTest.outerStaticNum);

System.out.println(new StaticInnerClassTest().outerNum);

}

}

下面说一下使用内部类(定义变量,创建实例和作为父类被继承):

1.在外部类内部使用内部类:这种与平时使用普通类没有太大区别。一样可以直接通过内部类类名来定义变量,通过new调用内部类构造器来创建实例。

区别在于:不要在外部类的静态成员(包括静态方法和静态初始化块)中使用非静态内部类,因为静态成员不能访问非静态成员。

2.在外部类以外的使用非静态内部类:内部类不能使用private访问控制权限,private修饰的内部类只能在外部类内部使用。

省略访问控制符的内部类,只能被与外部类处于同一包中的其它类所访问。

使用protected修饰的内部类,可被与外部类处于同一个包中的其它类和外部类的子类所访问。

使用public修饰的内部类,可以在任何地方被访问。

在外部类以外的地方定义内部类(包括静态和非静态两种)变量的语法如下:OuterClass.InnerClass varName

由于非静态内部类的对象必须寄生在外部类的对象里,因此创建非静态内部类对象之前,必须先创建其外部类对象。在外部类以外的地方创建非静态内部类实例的语法如下:

OuterInstance.new InnerConstructor()

示例代码如下:

class Out{

class Inner{

public Inner(String msg){

System.out.println(msg);

}

}

}

public class UseInnerClass {

public static void main(String[] args) {

Out.Inner inner;//定义内部类变量

Out out=new Out();//创建外部类示例

inner=out.new Inner("测试");  //创建非静态内部类实例

//也可以采用如下方式来创建

Out.Inner in=new Out().new Inner("测试");

}

}

当创建一个子类时,子类构造器总会调用父类的构造器,因此在创建非静态内部类的子类时,必须保证让子类构造器可以调用非静态内部类的构造器,调用非静态内部类的构造器时,

必须存在一个外部类对象。示例代码如下:

public class SubClass extends Out.Inner{

public SubClass(Out out, String msg) {

out.super(msg);//通过传入的Out对象显式调用Inner构造器

}

}

3.在外部类以外使用静态内部类:在外部类以外的地方创建静态内部类实例的语法如下:new OutClass.InnerConstructor();示例代码如下:

public class StaticOut {

static class StaticIn{

public StaticIn(){

System.out.println("静态内部类构造器");

}

}

public static void main(String[] args) {

StaticOut.StaticIn in=new StaticOut.StaticIn();

}

}

最后说一下匿名内部类:匿名内部类适合创建只需要一次使用的类。当创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复调用。

匿名内部类示例代码如下:

abstract class Demo {

public abstract void function();

}

public class Person{

public static void main(String[] args) {

Demo demo=new Demo(){

@Override

public void function() {

System.out.println("内部匿名类方法");

}

};

demo.function();

}

}

下面再举一个接口使用匿名内部类的例子:示例代码如下:

interface Product{

public double getPrice();

public String getName();

}

public class AnonymousTest {

public void test(Product p){

System.out.println(p.getName()+":"+p.getPrice());

}

public static void main(String[] args) {

AnonymousTest at=new AnonymousTest();

at.test(new Product(){

@Override

public double getPrice() {

return 4.8;

}

@Override

public String getName() {

return "西红柿";

}

});

}

}






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值