《Java 编程思想》学习笔记 09 | 内部类

1.在外部类的普通方法里可以直接创建内部类对象

public class Outer {
    private class Inner {
        Inner() {}
    }
    
    public void show() {
        Inner inner = new Inner();  //直接创建
    }
}

2.在main方法里,没有外部类对象的引用就无法创建普通内部类对象,静态内部类除外

  1. 可以使用.this.new来获取外部类对象的引用
  2. 没有外部类对象的引用就无法创建内部类对象
  3. 其中使用.new语法获得的外部类对象的引用可以拿来创建内部类对象
  4. 静态内部类不需要外部类对象的引用也可以创建
public class Outer {
    
    private class Inner {
        Inner() {}
    }
    public static class StaticInner {
        StaticInner() {}
    }
    
    public static void main(String[] args) {
        Outer o = new Outer();
        Outer.Inner inner1 = o.new Inner(); //创建普通内部类需要用.new获取外部类对象的引用
        Outer.StaticInner inner2 = new Inner(); //创建静态内部类不需要使用.new获取外部类对象的引用
    }
}
  1. 内部类对象会暗自的链接到创建它的外部类对象上,也就是说,当创建内部类对象时必须使用外部类对象的引用,,并且创建得到的内部类对象默认拥有其外部类对象的引用,所以内部类对象拥有其外部类对象所有成员的访问权限,当使用内部类对象访问其外部类对象的成员时,使用的就是这个引用。
  2. 而静态内部类之所以不用外部类对象的引用也可以创建的原因是它是静态的,它和外部类对象无法进行绑定,也就丧失了对可能创建的不同外部类对象的成员的访问权限,换句话说静态内部类只能访问独立于外部类对象之外的外部类的静态成员

3.内部类可以创建在外部类的普通方法中也可以创建在特定作用域里(如if语句的作用域)

但是这样做之后此内部类就不是外部类的一部分,此时的内部类只属于特定的方法与作用域,内部类在它们之外将无法被访问。

4.匿名内部类

  1. 匿名内部类的创建:new 类名(参数)或接口名() {匿名内部类具体定义};。此时创建的匿名内部类继承了new后面的那个类或者实现了new后面的那个接口。
  2. 并且匿名内部类最多只能继承一个类或实现一个接口。
  3. 记住,由于匿名内部类自动是继承了基类的,所以说,所有与继承有关的机制都适用于匿名内部类。并且匿名内部类没有名字,也就是说,无法创建类型为匿名内部类的引用,再深入点也就是说,匿名内部类里的方法必须是基类里有的,然后匿名内部类再去重写父类的方法假如说你在匿名内部类里写了一个基类没有的新方法,那你无论如何也没有办法去调用这个方法:因为你通过匿名内部类创建的对象引用一定是基类的,而基类无法调用子类特有的新方法
  4. 匿名内部类的小用法:创建一个方法,返回类型为匿名内部类继承的类或实现的接口,用return接new的形式来给予匿名内部类的定义空间,从而达到既定义了匿名内部类,又得到了能够返回该匿名内部类向上转型后的基类类型的方法:
//基类
class Inner { 
    public Inner() {
    }
    public void show() {
        System.out.println("这是匿名内部类的基类");
    }
}

public class Outer {
    
    public Inner inner(int i) {
        return new Inner(i) {
                public void show() {
                    System.out.println("这是匿名内部类"); //重写基类Inner的show方法
                }
            };
    }
    
    public static void main(String[] args) {
        Outer outer = new Outer();
        Inner inner = outer.inner(); //通过Outer对象调用inner方法来创建一个自动向上转型为Inner的匿名内部类对象
        inner.show(); //调用被匿名内部类重写后的show方法
    }

}
/*
* Output:
* 这是匿名内部类
*/
/*
* 如上所示,12~17行是匿名内部类的定义,该匿名内部类没有名字。
* 并且自动继承了Inner类(而不是说该匿名内部类是Inner)。
*/

5.匿名内部类没有构造方法,因为它没有名字,但可以使用“实例初始化”来作为匿名内部类的唯一构造器

//基类
class Inner { 
    public Inner() {}
}

public class Outer {
    public Inner inner() {
        return new inner() {
            private int num;
            {
                num = 47; //“实例初始化作为匿名内部类的唯一构造器”
            }
        };
    }
}

6.在匿名内部类之外的对象要想在匿名内部类内部被使用,那么它们只能是​final

//基类
class Inner { 
    public Inner() {}
}

public class Outer {
    
    public Inner inner(final String s) { //在匿名内部类被使用的对象只能是final的
        return new inner() {
            privaet String name = s; //在匿名内部类被使用的对象只能是final的
            System.out.println(s);
        };
    }
    
    public static void main(String[] args) {
        Outer outer = new Outer();
        Inner inner = outer.inner("我是final的");
    }
}

tip:Java里的字符串类型默认是final,至于为什么,《Java编程思想》之后应该会说。

7.再访工厂模式:使用匿名内部类来使工厂模式更加优雅

原来的工厂模式:

interface Game {
    void play();
}
class checkers implements Game {
    public void play() {
        System.out.println("Checkers is very funny!");
    }
}
class chess implements Game {
    public void play() {
        System.out.println("Chess is very funny!");
    }
}
//****************************************************//
interface GameFactory {
    Game getGame();
}
class checkersFactory implements GameFactory {
    public Game getGame() {
        return new chcekers();
    }
}
class chessFactory implements GameFactory {
    public Game getGame() {
        return new chess();
    }
}
//****************************************************//
public class Games {
    public static void playGame(GameFactory factory) {
        Game game = facory.getGame();
        game.play();
    }
    public tatic void main(String[] args) {
        playGame(new checkersFactory());
        palyGame(new chessFactory());
    }
}

使用匿名内部类的工厂模式:

interface Game {
    void play();
}
interface GameFactory {
    Game getGame();
}
class Checkers implements Game {
    public void play() {
        System.out.println("Checkers is very funny!");
    }
    public static GameFactory factory = new GameFactory() {
        public Game getGame() {return new Checkers();}
    };
}
class Chess implements Game {
    public void play() {
        System.out.println("Chess is very funny!");
    }
    public static GameFactory factory = new GameFactory() {
        public Game getGame() {return new Chess();}
    };
}
//****************************************************//
public class Games {
    public static void playGame(GameFactory factory) {
        Game game = factory.getGame();
        game.play();
    }
    public static void main(String[] args) {
        playGame(Checkers.factory);
        playGame(Chess.factory);
    }
}

8.接口中的内部类:接口中的内部类自动是public static的

接口中的内部类甚至可以实现其外围接口:

public interface Outer {
    void show() {
        System.out.println("这是外围接口");
    }
    
    class Inner implements Outer { //Inner类由于在接口中,所以自动是public static的
        public void show() {
            System.out.println("这是接口中的内部类");
        }
    }
    
    public static void main(String[] args) {
        new Inner().show();
    }
}
/* Output:
* 这是接口中的内部类
*/

9.内部类最吸引人的原因:它可以实现“多重继承”

由于每个内部类继承一个类或实现一个接口的时候是不需要考虑外围类的,也就是说,每个内部类都能独立地继承一个类或实现一个接口而不会去在乎其外围类是否已经继承了一个类或实现了一个接口!所以,从另一个角度来说,当某个外围类继承了一个A类,而其内部类继承了B类,那么就相当于这个外围类实现了“多重继承”,这个外围类可以得到A类和B类的对象

class A {}
class B {}
public class Outer extends A {
    public B getB() { //getB()方法就可以得到一个B类的对象
        return new B() {
            
        };
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        A a = new Outer();
        B b = new Outer().getB();  //间接就使Outer类继承了B类,从而间接实现了多重继承
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值