内部类的分类与作用
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
*/
代理类和被代理类实际调用底层对象是同一个对象。