菜鸟成长日记:Java基础篇8 --- 内部类

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了菜鸟成长日记:Java基础篇8 --- 内部类相关的知识,希望对你有一定的参考价值。

(一)、内部类的概念
  1、内部类是个编译时的概念,一旦编译成功后,它就与外围类属于两个完全不同的类(当然他们之间还是有联系的)。
  2、对于一个名为OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,
       会出现这样两个class文件:OuterClass.class和OuterClass$InnerClass.class。
  3、使用内部类最大的优点就在于它能够非常好的解决多重继承的问题
  4、内部类提供了更好的封装,除了该外围类,其他类都不能访问。

(二)、内部类的分类
  Java中内部类主要分为成员内部类、局部内部类、匿名内部类、静态内部类。

  一、成员内部类:
    1、成员内部类是外围类的一个成员,所以他是可以无限制的访问外围类的所有成员属性和方法
    2、尽管是private的,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。
    3、成员内部类中不能存在任何static的变量和方法;
    4、成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。

  代码示例:

/**
 * 成员内部类测试
 * @author wangchong
 * @date 2017年10月23日 下午3:30:50
 */
public class OuterClassTest1{

    public String outerName;
    
    public OuterClassTest1(String outerName){
        this.outerName = outerName;
    }
    
    /**
     * 获取内部类的一个引用
     * @return
     */
    public InnerClass getInnerClass() {
        
        return new InnerClass(outerName);
    }
    
    /**
     * 内部类
     * @author wangchong
     * @date 2017年10月23日 下午5:12:41
     */
    private class InnerClass{
        
        private String innerName;
        
        private InnerClass(String outerName) {
            this.innerName = outerName;
        }
        
        /**
         * 得到外部类
         * @return
         */
        private OuterClassTest1 getOuterClassTest1() {
            return OuterClassTest1.this;
        }
        
    }    
    
    public static void main(String[] args) {

        OuterClassTest1 outerTest1 = new  OuterClassTest1("names");
        // 获取内部类的实例的第一种方式
        OuterClassTest1.InnerClass innerTest1 = outerTest1.getInnerClass();
        // 第二种方式
        OuterClassTest1.InnerClass innerTest2 = outerTest1.new InnerClass(outerTest1.outerName);
        // 上面两种方式对比,明显第一种方式更好
        
        System.out.println(innerTest1.getOuterClassTest1().outerName + "," + innerTest1.innerName);
        System.out.println(innerTest1.getOuterClassTest1().outerName + "," + innerTest2.innerName);
    }
}


  二、局部内部类:
    嵌套在方法和作用域内的,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的。
  所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。

  代码示例:

/**
 * 局部内部类测试
 * @author wangchong
 * @date 2017年10月23日 下午5:13:31
 */
public class OuterClassTest2 {

    public int limitNum;
    
    public void setNum(int num){
        this.limitNum = num;
    }
    
    // 定义在作用域的内部类
    public void getClass1(int n){
        if (n > limitNum) {
            
            /**
             * 定义在作用域的内部类
             * @author wangchong
             * @date 2017年10月23日 下午5:39:41
             */
            class InnerClass1 {
                // 内部条件
                private int innerNum;
                
                public InnerClass1(int innerNum){
                    this.innerNum = innerNum;
                }
                
                private void getMessage(int n) {
                    if(n <= innerNum){
                        System.out.println("值通过外条件,低于内部条件");    
                    }else {
                        System.out.println("值通过外条件,高于内部条件");
                    }
                }
            }
            
            InnerClass1 innerClass = new InnerClass1(10);
            innerClass.getMessage(n);    
        }
    }
    
    // 定义在方法里
    public int getNum2(int num){
        /**
         * 定义在方法里的内部类
         * @author wangchong
         * @date 2017年10月23日 下午7:10:20
         */
        class InnerClass2 extends OuterClassTest2 {
            public int limitNum = (num + 1);
            
            public int getLimitNum(){
                return limitNum;
            }
        }
        
        return (new InnerClass2()).getLimitNum();
    }
    
    public static void main(String[] args) {

        OuterClassTest2 outerClass = new OuterClassTest2();
        outerClass.setNum(1);
        outerClass.getClass1(8);
        System.out.println(outerClass.getNum2(10));
        
    }
}


  三、匿名内部类:匿名内部类也就是没有名字的内部类
  1、正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写
  2、使用匿名内部类有个前提条件:必须继承一个父类或实现一个接口
  3、如果一个类有一个父类或者父接口,且只使用一次,则此时可以使用匿名内部类

  代码实现:

/**
 * 匿名内部类
 * @author wangchong
 * @date 2017年10月23日 下午7:23:27
 */
public class OuterClassTest3 {

    public static void main(String[] args) throws InterruptedException {
        // 匿名内部类实现Runnable接口
        Runnable r = new Runnable() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        Thread t = new Thread(r);
        t.start();
        
        Thread.sleep((long) Math.random()*1000);
        System.out.println();
        
        // 匿名内部类继承Thread类
        Thread z = new Thread() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        z.start();
    }
}


  四、静态内部类:使用static修饰的内部类我们称之为静态内部类或者嵌套内部类。
    1、非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有
    2、静态内部类的创建是不需要依赖于外围类的。
    3、静态内部类不能使用任何外围类的非static成员变量和方法。

  代码示例:

/**
 * 静态内部类
 * @author wangchong
 * @date 2017年10月23日 下午7:33:35
 */
public class OuterClassTest4 {

    private String className;
    
    public OuterClassTest4(String className){
        this.className = className;
    }
    /**
     * 静态内部类
     * @author wangchong
     * @date 2017年10月23日 下午8:04:59
     */
    public static class innerClass1 {
        private static String name1;
        private int age;
        
        public innerClass1(String name, int age){
            this.name1 = name;
            this.age = age;
        }
        
        public void showMessage(){
            // System.out.println("姓名:" + name2 + ",年龄:" + age + ",年级:" + className);  编译报错,不能使用外部的非静态属性和方法
            System.out.println("姓名:" + name1 + ",年龄:" + age);
        }
    }
    
    /**
     * 非静态内部类
     * @author wangchong
     * @date 2017年10月23日 下午8:05:16
     */
    public class innerClass2 {
        private String name2;
        private int age;
        
        public innerClass2(String name, int age){
            this.name2 = name;
            this.age = age;
        }
        
        public void showMessage(){
            System.out.println("姓名:" + name2 + ",年龄:" + age + ",年级:" + className);
        }
        
    }
    
    public static void main(String[] args){
        OuterClassTest4 outerClass = new OuterClassTest4("三年级二班");
        // 静态内部类的创建不依赖于外部类
        innerClass1 inner1 = new innerClass1("小明", 10);
        OuterClassTest4.innerClass2 inner2 = outerClass.new innerClass2("小红", 9);
        inner1.showMessage();
        inner2.showMessage();
        
    }
}

























以上是关于菜鸟成长日记:Java基础篇8 --- 内部类的主要内容,如果未能解决你的问题,请参考以下文章

菜鸟成长日记:Java基础篇2 --- 动态参数类型

菜鸟成长日记:Java基础篇4 --- 正则表达式

菜鸟的linux成长日记-bash基础特性2

菜鸟成长日记:开发工具箱 --- UML的简单介绍

Java学习日记基础篇—— 抽象类接口final

转行小白成长路-java篇