第六章 接口与内部类(2)

内部类的分类与作用

        Java内部类是一种特殊类型的类,它被定义在一个类的内部。根据其作用域,内部类可以分为四种:局部内部类,匿名内部类,静态内部类,成员内部类。

        为什么需要内部类:

        1、内部类可以对同一包中的其他类隐藏;

        2、内部类方法可以访问定义这个类的作用域中的数据,包括私有的数据。

局部内部类

        局部内部类不能用public或private访问说明符进行声明,它的作用域被限定在声明这个局部类的块中。

        局部内部类的优势:对外部类完全的隐藏起来,外部类的其他方法也无法访问局部内部类。

public class OutClass {
    private int i = 10;
    public void testInnerClass(String name){
        class InnerClass{
            public void test(){
                System.out.println(" name = " + name + " age = " + i);
            }
        }
        // 局部内部类的调用
        InnerClass ic = new InnerClass();
        ic.test();
    }
}


// 测试方法
public class Main {

    public static void main(String[] args) throws CloneNotSupportedException {
        OutClass outClass = new OutClass();
        outClass.testInnerClass("James");
    }
}

上面代码输出结果: name = James age = 10

局部内部类可以直接访问外部类的私有属性,但是外部方法无法感知并获取局部内部类的存在。

匿名内部类

        1、对接口实例化

public interface UnnamedInterface {
    void test();
}

        不清楚接口的实现类的情况下,匿名内部类可以实现接口的实例化调用。如下面代码所示

public class UnnamedClassTest {

    public static void main(String[] args) {
        UnnamedInterface unnamedInterface = new UnnamedInterface() {
            @Override
            public void test() {
                System.out.println("测试匿名类");
            }
        };
        unnamedInterface.test();
    }
}

        2、重写父类实现

public class UnnamedFuClass {
    public void test(){
        System.out.println("父类的方法");
    }
}

        匿名内部类实现重写父类方法的实现

public class UnnamedClassTest {

    public static void main(String[] args) {
        UnnamedFuClass unnamedFuClass = new UnnamedFuClass(){
            @Override
            public void test(){
                System.out.println("匿名内部类的方法");
            }
        };
        unnamedFuClass.test();
    }
}
// 输出结果:匿名内部类的方法

        匿名内部类在父类和接口中可以起到简化代码的作用。因为可以省去创建子类和实现类的过程, 匿名内部类的最终产物是子类/实现类对象。

静态内部类与普通成员内部类

        静态内部类只能访问外部类的静态属性,不能访问普通成员属性;静态内部类的创建可以直接new静态内部类本身。

        成员内部类能访问外部类的所有属性;成员内部类的创建需要先new外部内再new内部类。

public class StaticInnerClassTest {
    private String normalVal = "普通成员变量";
    private static String staticVal = "静态成员变量";
    public static void main(String[] args) {
        Inner inner = new StaticInnerClassTest().new Inner();
        inner.test();
        StaticInner staticInner = new StaticInner();
        staticInner.test();
    }
    class Inner{
        private String innerVal = "普通内部类静态变量";
        public void test(){
            System.out.println(innerVal +  "," + normalVal  + "," + staticVal );
        }
    }
    static class StaticInner{
        private static String innerVal = "静态内部类静态变量";
        private String innerNormalVal = "静态内部类普通变量";
        public void test(){
            System.out.println(innerVal +  "," + innerNormalVal + "," + staticVal );
        }
    }
}
/**
* 输出结果:
*    普通内部类静态变量,普通成员变量,静态成员变量
*    静态内部类静态变量,静态内部类普通变量,静态成员变量   
*/

代理Proxy

        利用代理可以在运行时创建实现一组给定接口的新类。
        spring的JDK 动态代理机制,JDK动态代理是一种实现在Java中实现AOP编程的方式。它可以在jvm运行时创建一个代理对象(动态地创建某个接口的实例),用于替换原始对象并截取其方法调用。

        目标接口

public interface Target {
    void sayHello();
}

        目标实现

public class TargetImpl implements Target{
    @Override
    public void sayHello() {
        System.out.println("hello world");
    }
}

        创建一个代理类如下:实现InvocationHandler接口创建自己的调用处理器(在该处理器中重写invoke方法,可以动态的添加实现额外的逻辑,AOP的实现原理)

public class TraceHandler implements InvocationHandler {
    private Object target;
    public TraceHandler(Object t){
        this.target = t;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.print(target);
        System.out.print("." + method.getName()+"(");
        if(args != null){
            for (int i = 0; i < args.length; i++) {
                System.out.print(args[i]);
                if(i < args.length - 1){
                    System.out.print(",");
                }
            }
        }
        System.out.println(")");
        System.out.println("代理类可以实现额外的逻辑");
        return method.invoke(target,args);
    }
}

测试类

public class ProxyTest {
    public static void main(String[] args) {
        // 被代理对象
        Target t = new TargetImpl();
        System.out.println("t = " + t);
        t.sayHello();
        TraceHandler handler = new TraceHandler(t);
        Target t2 = (Target) Proxy.newProxyInstance(t.getClass().getClassLoader(),new Class[]{Target.class},handler);
        t2.sayHello();
    }
}
/**
输出结果:
    t = chapter6.TargetImpl@3498ed
    hello world

   
    chapter6.TargetImpl@3498ed.sayHello()
    代理类可以实现额外的逻辑
    hello world
*/

代理类和被代理类实际调用底层对象是同一个对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值