从头认识java-12.6 接口与类型信息(怎么绕过接口直接调用类的所有方法)

这一章节我们来讨论一下接口与类型信息。

在之前的章节里面我们提到接口,父类引用子类对象,然后把方法给缩窄了,但是我们这一章节学习到反射,这个约束就变得没有那么严格。

我们来看看下面的例子:

package com.ray.ch11;

public class Test {
	public static void main(String[] args) {
		Person man = new Man();
		man.sleep();
		man.run();
		// man.say();//error
	}
}

interface Person {

	public void sleep();

	public void run();
}

class Man implements Person {
	public void say() {
	}

	@Override
	public void sleep() {
	}

	@Override
	public void run() {
	}
}

我们一般的代码就会向上面一样,直接定义接口,然后接口指向实现的类。一般的情况就像上面一样,方法给变少了。但是,我们修改一下方法:

package com.ray.ch11;

public class Test {
	public static void main(String[] args) {
		Person man = new Man();
		man.sleep();
		man.run();
		// man.say();//error
		if (man instanceof Man) {
			Man man2 = (Man) man;
			man2.say();
		}
	}
}

interface Person {

	public void sleep();

	public void run();
}

class Man implements Person {
	public void say() {
	}

	@Override
	public void sleep() {
	}

	@Override
	public void run() {
	}
}

我们修改了一下,通过isInstanceOf方法,来向下转型,这样我们就可以得到Man里面所有的方法,甚至是下面的代码:

package com.ray.ch11;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test {
	public static void main(String[] args) {
		try {
			Class<?> manClass = Class.forName("com.ray.ch11.Man");
			Man man = (Man) manClass.newInstance();
			Method[] methods = man.getClass().getDeclaredMethods();
			for (Method method : methods) {
				System.out.println(method.getName());
			}
			Method sayMethod = manClass.newInstance().getClass()
					.getDeclaredMethod("say");
			sayMethod.setAccessible(true);
			sayMethod.invoke(man);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}

interface Person {

	public void sleep();

	public void run();
}

class Man implements Person {
	private void say() {
		System.out.println("method say");
	}

	@Override
	public void sleep() {
	}

	@Override
	public void run() {
	}
}
通过上面的代码,我们直接调用类里面所有的方法,包括私有方法。

这个对于封装来说是比较致命的,因此,我们提供的服务端代码一般都隐藏了类的信息,例如:

package com.ray.ch11;

public class Test {

	public static Person makePerson() {
		return new Man();
	}

	public static void main(String[] args) {
		Person person = makePerson();
	}
}

interface Person {

	public void sleep();

	public void run();
}

class Man implements Person {
	private void say() {
		System.out.println("method say");
	}

	@Override
	public void sleep() {
	}

	@Override
	public void run() {
	}
}

我们通过一个方法隐含了类的实现,全部是以接口的形式对外展现,这样就可以避免了上面的一些问题。


总结:这一章节主要讲述了接口与类型信息的内容,需要注意跨过接口直接调用类的情况。


这一章节就到这里,谢谢。

-----------------------------------

目录




你可能感兴趣的:(从头认识java-12.6 接口与类型信息(怎么绕过接口直接调用类的所有方法))