• 内部类说白了就是类中有类

内部类:嵌套类

外部类:宿主类



  • 内部类主要有以下作用:记住了3个字:多继承。。。

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

2,内部类可以访问外部类的私有数据,外部类不能访问内部类的实现细节,比如字段。

3,匿名内部类适合用于那些仅需要一次使用的类。比如在命令模式中,当需要传入一个Command对象时,使用匿名内部类将更加方便。

  • 内部类分类,主要有下面4种:

非静态内部类;静态内部类;局部内部类;匿名内部类

  • 非静态内部类

值得注意的是:外部类的上一级程序单元是包,所以他只有2个作用域:public和默认的default。

       内部类的上一级程序单元是外部类,他就有4个作用域:可以使用任意的访问控制符。



/**
*
* @version 1L
* @author LinkinPark
* @since 2014-11-5
* @motto 梦似烟花心似水,同学少年不言情
* @desc ^在linkin类中定义一个binger的非静态内部类,并在binger类的实例方法中直接访问linkin的实例属性
*
*/
public class Linkin {
private String name = "LinkinPark"; private class Binger {
private String andress = "Binger"; public String getAndress() {
return andress;
} public void setAndress(String andress) {
this.andress = andress;
} // 非静态内部类的实例方法
public void test() {
System.out.println("内部类中的属性" + andress);
System.out.println("外部类中的属性" + name);
}
} //外部类的实例方法
public void test(){
Binger binger = new Binger();
binger.test();
} public static void main(String[] args) {
Linkin linkin = new Linkin();
linkin.test();
} }



编译上面的程序,可以看到文件所在路径生成了2个class文件:



成员内部类(包括静态内部类,非静态内部类)的class总是这样子:OutClass$ InnerClass.class。

注意上面的代码:当调用非静态内部类的实例方法时,必须要有一个非静态内部类的实例,而且这个实例必须寄存在外部类实例中。

那么问题来了:若外部类字段,内部类字段,内部类方法变量同名,则具体的访问方式是怎么样的呢?

1,访问外部类的字段:外部类类名.this.字段

2,访问内部类字段:this.字段

3,访问内部类方法的局部变量:字段

代码如下:

public class Linkin {
private String name = "LinkinPark..."; private class Binger {
private String name = "Binger..."; // 非静态内部类的实例方法
public void test() {
String name = "huhu...";
System.out.println("局部变量的属性" + name);
System.out.println("内部类中的属性" + this.name);
System.out.println("外部类中的属性" + Linkin.this.name);
}
} //外部类的实例方法
public void test(){
Binger binger = new Binger();
binger.test();
} public static void main(String[] args) {
Linkin linkin = new Linkin();
linkin.test();
} }

  • 在外部类以内访问非静态内部类

非静态内部类对象必须寄存在外部类对象中,但是外部类对象不一定非要有非静态内部类对象寄存其中。

因此外部类对象访问非静态内部类成员时,可能非静态内部类对象就压根没存在,反过来:要是非静态内部类对象访问外部类成员时,外部类对象一定存在的。

public class Linkin {
private String name = "LinkinPark..."; private class Binger {
private String name = "Binger...";
private String huhu = "Binger..."; // 非静态内部类的实例方法
public void test() {
String name = "huhu...";
//注意了:java不允许在非静态内部类中定义静态成员:包括静态方法,静态属性,静态初始化块。。。
//static String name = "huhu...";
System.out.println("局部变量的属性" + name);
System.out.println("内部类中的属性" + this.name);
System.out.println("外部类中的属性" + Linkin.this.name);
}
} //外部类的实例方法
public void test(){
//注意了:外部类不允许直接访问非静态内部类的实例属性,如果确实需要访问的话,必须显式new内部类对象出来
//System.out.println(huhu);
System.out.println(new Binger().huhu);
Binger binger = new Binger();
binger.test();
} public static void main(String[] args) {
//注意了:外部类的静态成员也不可以直接使用非静态内部类,下行代码编译报错。
//new Binger();
Linkin linkin = new Linkin();
linkin.test();
} }
  • 在外部类以外访问非静态内部类

内部类不能是private修饰,否则不能访问,外部类以外的地方定义内部类变量。类型:OuterClass.InnerClass varName。

非静态内部类对象是存放在外部类的对象里的,因此在创建非静态内部类对象之前,必须先创建其外部类的对象。OuterInstance.new InnerClass([参数列表])。

class Linkin {
String name = "LinkinPark..."; class Binger {
String name = "Binger..."; public Binger(){
} public Binger(String name){
this.name = name;
} public void test() {
System.out.println("帝王注定孤独,江山与他何干...");
}
} } //其实在外部类中或者外部类外创建内部类对象(比如一个子类对象),都要使得内部类保持外部类对象的一个引用。
//前者可以通过外部类对象直接new内部类出来,后来将外部类作为参数传入内部类的子类构造器中。
public class LinkinTest extends Linkin.Binger{ //No enclosing instance of type Linkin is available due to some intermediate constructor invocation
//下面的构造器必须在,而且还要必须传入一个外部类,因为非静态内部类对象中必须存在一个外部类对象的引用的
public LinkinTest(Linkin linkin){
linkin.super();
//linkin.super("huhu");
}
public static void main(String[] args) {
//创建内部类对象
Linkin.Binger binger = new Linkin().new Binger("忽忽");
//访问属性
System.out.println(new Linkin().name);//LinkinPark...
System.out.println(new Linkin().new Binger().name);//Binger...
System.out.println(new Linkin().new Binger("忽忽").name);//忽忽
} }
  • 静态内部类

使用static修饰内部类,该内部类属于其外部类,而不属于外部类的实例;静态内部类可包括静态成员也可包括非静态成员。

根据静态成员不能访问非静态成员的规定,所以静态内部类不能访问外部类实例成员,只能访问外部类的静态成员。即使是静态内部类的方法也不可以。

为毛静态内部类实例方法中也不能访问外部类的实例属性?

静态内部类对象不是寄存在外部类对象中的,而是寄存在外部类的类中。如果允许上面的操作,但是找不到外部类的实例对象,肯定要引起错误的呀。

/**
*
* @version 1L
* @author LinkinPark
* @since 2014-11-5
* @motto 梦似烟花心似水,同学少年不言情
* @desc ^static不可以修饰外部类,但是可以修饰内部类
*/
class Linkin {
String name1 = "LinkinPark...";
static String name3; static class Binger {
String name2 = "Binger..."; public Binger(){
} public Binger(String name2){
this.name2 = name2;
} public void test() {
//Cannot make a static reference to the non-static field name1
//静态成员不能访问非静态成员
//System.out.println(name1);
System.out.println(name3);
}
} }



  • 在外部类之内访问静态内部类

public class Linkin {
    private String name = "LinkinPark";
    private static int age = 25;     static class Binger {
        private String name1 = "Binger";
        private static int age1 = 24;         public void show() {
            // System.out.println(name);不能访问:静态的不能访问非静态的
            System.out.println(new Linkin().name);// 可以访问
            System.out.println(age);// 可以访问
        }
    }     public void test() {
        // System.out.println(name1);不能访问
        // System.out.println(age1);不能访问
        System.out.println(new Binger().name1);
        System.out.println(Binger.age1);
        new Binger().show();
    }     public static void main(String[] args) {
        new Linkin().test();//Binger 24 LinkinPark 25
    }
}
  • 在外部类以外访问静态内部类

因为静态内部类是外部类的类成员,因此在创建内部类对象时不需创建外部类的对象;

创建内部类对象:new OuterClass.InnerClass([参数列表])。注:静态内部类的全名应该是OuterClass.InnerClass,所以要看作是一个整体。

public class Linkin {
    static String name3;     static class Binger {
        static String name2;
        public void show(){
            System.out.println("静态内部类实例方法...");
        }
        public static void staticShow(){
            System.out.println("静态内部类静态方法...");
        }
    }     public static void main(String[] args) {
        Linkin.Binger binger = new Linkin.Binger();
        Linkin.Binger.staticShow();//调用静态内部类静态方法
        binger.show();//调用静态内部类的实例方法
    }
}
  • 局部内部类

对于局部成员而言,不管是局部变量,还是局部内部类,他们的上一级程序单元是方法,而不是类,所以使用static完全没有意义。不仅如此,因为局部成员的作用域是所在的方法,其他程序单元永远不能访问另一个方法中的局部变量,所以局部变量不可以使用访问控制符修饰。

局部内部类:定义在方法里的内部类。

特点:不能在宿主类以外的地方使用,局部内部类也不能使用访问修饰符和static修饰。

局部内部类只能访问方法中final修饰的局部变量:因为final修饰的变量相当于一个常量,其生命周期超出了方法运行的生命周期。

关于上面这一点,我也不是很懂,记住就好了。其实一般也不会在一个方法中来定义一个内部类,这个有点复杂了,就好比不会在一个接口里面定义一个内部接口,我是没见过。

public class Linkin {
    public void test(){
        class Binger{
            
        }
        class Binger1{
            
        }
    };
    public static void main(String[] args) {
        final int age = 0;
        class Binger{
            String name;
            public void test(){
                //注意了:局部内部类中访问局部变量必须使用final修饰那个变量
                System.out.println(age);
            }
        }
        class Binger1 extends Binger{
            String name1;
        }
        Binger1 binger1 = new Binger1();
        binger1.name = "LinkinPark...";
        binger1.name1 = "binger...";
        System.out.println(binger1.name+"---"+binger1.name1);
    }
}

编译上面的程序看到有5个class,这表明局部内部类的class文件总是以下命名方式:OutClass$InnerClass.class,注意到局部内部类的文件名的class文件比内部类的class文件多了一个数字,这是因为同一个类中不可能有2个同名的成员变量,但是同一个类中可能有2个或者2个以上的同名的局部内部类,所以java为局部内部类的class文件增加了一个数字,用于区分。



  • 匿名内部类

适合只使用一次的类。1,不能是抽象类,因为系统在创建匿名内部类的时候,会立即创建匿名内部类的对象,2,匿名内部类不能定义构造器,因为匿名内部类没有类名。

格式:new 父类构造器([实参列表]) 或 接口()

   {

//匿名内部类的类体部分

   }

注意:匿名内部类必须继承一个父类或者实现一个接口,但最多只能一个父类或实现一个接口;

创建匿名[Anonymity]内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复使用。匿名内部类访问局部变量时也必须使用final修饰那个变量。



<pre name="code" class="java">public class Linkin {
//定义一个方法,其中的参数要用到下面的抽象类
public static void test(Binger binger){
System.out.println(binger.getName());
System.out.println(binger.test());
}
//定义一个方法,其中的参数要用到下面的接口
public static void test1(Ihuhu huhu){
System.out.println(huhu.test());
}
public static void main(String[] args) {
//直接传入一个匿名内部类,只是在调用这个方法的时候使用一次
Linkin.test(new Binger(){ @Override
//这里是必须要实现的抽象方法
public String test() {
return "这里把name的get方法返回了。。。";
} @Override
//匿名内部类当然可以重写继承过来的方法
public String getName() {
return "linkinPark...";
} }); Linkin.test1(new Ihuhu(){ @Override//必须要实现接口里面的所有的方法呀
public String test() {
return "huhu...";
} });
}
} abstract class Binger{
private String name = "binger...";
public Binger(){ }
public Binger(String name){
this.name = name;
} public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//定义一个抽象方法
abstract public String test();
} interface Ihuhu{
public String test();
}










linkin大话面向对象--内部类的更多相关文章

  1. linkin大话面向对象--闭包和回调

      先来理解2个概念:闭包和回调   什么是闭包? 闭包是一个可调用的对象,它记录了一些信息,这些信息来自于创建他的作用域.通过这个定义,可以看出内部类是面向对象的闭包,因为他不仅包含了外部类对象的信 ...

  2. linkin大话面向对象--类和对象

    我们每天在撸码,那么我们在敲什么东西呢?明显的我们在写类,写一个类,写一个接口,写某个接口里面写一些属性,在某个类里面写一个方法,然后以一个对象调用方法,对于j2ee来讲的话,可能还会写一些jsp,静 ...

  3. linkin大话面向对象--java关键字

    java中的关键字有以下几个,他们不能作任何其它的用途. 发现没,java中的关键字全是小写,java是严格区分大小写的. abstract  default  null  synchronized ...

  4. linkin大话面向对象--多态

    java引用变量有2个类型,一个是编译时类型,一个是运行时类型: 编译时类型:声明的类型,把它看做是什么东西 运行时类型:真正的类型,实际上指的是什么东西 如果编译时类型和运行时类型不同,就出现多态. ...

  5. linkin大话面向对象--GC和jar包

    GC java的垃圾回机制是java语言的重要机制之一.当程序创建对象,数组等引用类型实体时,系统都会在堆内存中为之分配一块内存区,对象就保存在这块内存区中.当这块内存不再被任何变量引用时,这块内存就 ...

  6. linkin大话面向对象--枚举

    枚举类(enum) 其实我们使用到枚举的地方还是很多的,其实我们可以完全人工的来实现枚举的功能.比如说我现在手里的项目我就是自己实现的枚举,说白了,枚举就是一个类的多例模式. 1,使用enum声明,默 ...

  7. linkin大话面向对象--接口

    接口(interface)的概念,掌握接口很重要,以后所有的编程都要面向接口编程.其实接口的内涵就7个字:规范和实现分离. 抽象类是从多个类中抽象出来的模板,若要将这种抽象进行得更彻底,就得用到一种特 ...

  8. linkin大话面向对象--包装类

    Java提倡的万物皆对象,但是数据类型的划分出现了基本数据类型和引用数据类型,那么我们怎么能把基本数据类型称为对象呢? 基本数据类型 包装类 byte Byte short Short int Int ...

  9. linkin大话面向对象--初始化块

    java使用构造器来对单个对象进行初始化操作,使用构造器先完成整个java对象的状态初始化,然后将java对象返回给程序,从而让整个java对象的信息更加完整.与构造器作用非常类似的是初始化块,它也可 ...

随机推荐

  1. PyQt4 的部件 -- CheckBox 单选框

    单选框具有两种状态:被选中或未被选中. 当用户选择或者取消选择时,单选框就会发射一个stateChanged()信号 # QCheckBox 单选框 # 本例创建一个用来改变窗口标题的单选框 impo ...

  2. 【RMQ】洛谷P3379 RMQ求LCA

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  3. 深入设计电子计算器(一)——CPU指令集设计

    版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/8254096.html 作者:窗户 Q ...

  4. Oracle之 11gR2 RAC 修改监听器端口号的步骤

    Oracle 11gR2 RAC 修改监听器端口号的步骤 说明:192.168.188.181 为public ip1192.168.188.182 为public ip2192.168.188.18 ...

  5. 86、flask之一些凌乱知识点

    本篇导航: session组件 上下文与内置函数 pymysql问题 模版问题 一.session组件 1.session组件简介 flask-session是flask框架的session组件,由于 ...

  6. 自定义MVC框架---第二章

    模型层的封装 模型层封装的原则 介绍: 模型层,也就是Model这一层,用来封装对数据库操作的封装 由于现在主流的编程思想还是OOP面向对象编程,也就是说项目的基本单位就是一个一个类文件,那么如何使用 ...

  7. JavaScript基础知识(正则表达式、字符串)

    23.正则表达式 作用:定义一个特定的验证字符串内容规则的表达式 注:正则表达式并不是JavaScript独有的:JavaScript支持正则表达式 var a = { };  // 定义一个空对象  ...

  8. DOM拓展

    DOM拓展 1.选择符API 所谓选择符API即是根据css选择符选择与某个模式相匹配的DOM元素,jQuery的核心就是通过css选择符查询DOM文档取得元素的引用,从而抛弃了原有繁琐的getELe ...

  9. JavaScript for in的缺陷

    for in 语句用来列举对象的属性(成员),如下 1 2 3 4 5 6 7 var obj = { name:"jack",       getName:function(){ ...

  10. 常见 Java 异常解释(恶搞版)

    常见 Java 异常解释:(译者注:非技术角度分析.阅读有风险,理解需谨慎o(╯□╰)o) java.lang ArithmeticException 你正在试图使用电脑解决一个自己解决不了的数学问题 ...