Java - 反射和泛型
阅读数:193 评论数:0
跳转到新版页面分类
python/Java
正文
1、类型信息
指程序能够在运行时发现和使用类型信息,我们一般使用两种方式来实现运行时对象和类的信息:传统的RTTI和反射机制。
(1)class对象
专门用来保存类的信息,所有类都是动态加载到JVM中的,在他们第一次使用的时候,类加载器会首先检查Class对象是否加载,如果没有,那么找到同名的class文件,然后加载字节码文件,验证代码的完整性和安全性,一旦这个类型的class对象加载到内存中,它将会用来创建所有此类的对象。
class对象的生成方式如下:
- Class.forName(“类名字符串”)
- 类名.class
- 实例对象.getClass()
package Refect;
class Demo{
//other code...
}
class hello{
public static void main(String[] args){
Class<?> demo1 = null;
Class<?> demo2 = null;
Class<?> demo3 = null;
try{
demo1 = Class.forName("Reflect.Demo");
}cathc(Exception e){
e.printStackTrace();
}
demo2 = new Demo().getClass();
demo3 = Demo.class;
}
System.out.println("类名称 "+demo1.getName());//Reflect.Demo
System.out.println("类名称 "+demo2.getName());//Reflect.Demo
System.out.println("类名称 "+demo3.getName());//Reflect.Demo
}
2、instanceof & isAssignableFrom
告诉我们对象是不是某个特定类型的实例。
isAssignableFrom 是用来判断一个类Class1和另一个类Class2是否相同或是另一个类的超类或接口。
3、反射
RTTI(运行时类型信息)和反射之间真正的区别只在于,对于RTTI来说,编译器在编译时打开和检查.class文件,而对于反射机制来说,.class文件在编译时是不可获取的,所以是在运行时打开和检查.class文件。
反射主要是指程序可以访问、检测和修改它本身或行为的一种能力。
package Reflect;
interface China{
public String name = "Rollen";
public int age = 20;
public void sayChina();
public void sayHello(String name,int age);
}
class Person implements China{
private String sex;
public Person(){};
public Person(String sex){this.sex = sex;}
public getSex(){return sex;}
public setSex(String sex){this.sex = sex;}
@Override
public void sayChina(){
System.out.println("hello, china");
}
@Override
public void sayHello(String name,int age){
System.out.println(name+" "+age);
}
}
class hello{
public static void main(String[] args){
Class<?> demo = null;
try{
demo = Class.forName("Reflect.Person")
}catch(Exception e){e.printStackTrace();}
//保存所有的接口
Class<?> intes[] demo.getInterfaces();
for(int i=0;i<intes.length;++i){
System.out.println("实现的接口 "+intes[i].getName());
//Reflect.China
}
//获得全部的构造函数
Constructor<?> cons[]= demo.getConstructors();
for(int i=0;i<cons.length;++i){
System.out.println("构造函数: "+cons[i]);
}
//通过反射调用其它类中的方法
try{
Method method = demo.getMethod("sayHello");
mehtod.invoke(demo.newInstance());
}catch(Exception e){e.printStackTrace();}
Object obj = null;
try{
obj = demo.newInstance();
}catch(Exception e){e.printStackTrace();}
//通过反射操作属性
Field field = demo.getDeclaredField("sex");
field.setAccessible(true);
field.set(obj,"男");
}
}
(1)获取Field
可以在运行时检查类的字段(成员变量)并且get/set它们的值。
Class aClass = ...//obtain class object
Field[] methods = aClass.getFields();
一旦你获得了一个Field实例,你可以像这样通过Field.getName方法获得字段名。
Field field = ... //obtain field object
String fieldName = field.getName();
Field field = aClass.getField("someField");
Object fieldType = field.getType();
获取和设置Field的值
Class aClass = MyObject.class
Field field = aClass.getField("someField");
MyObject objectInstance = new MyObject();
Object value = field.get(objectInstance);
field.set(objetInstance, value);
传递get和set方法的参数objectInstance必须是拥有该字段的实例。如果字段是静态字段,则传null作为get和set方法的参数。
在Java的反射使用中,如果字段是私有的, 那么必须要对这个字段设置
filed.setAccessible(true)
这样才可以正常使用,否则或报错:cannot access a member of...
4、泛型
(1)通配符
通配符的上界
? extends myClass其中“?”就是通配符,其上界为myClass,这句话代表myClass或其子类。
List<Apple> apples = new ArrayList<Apple>();
List<? extends Fruit> fruits = apples;
通配符的下界
? super myClass表示通配符的下界为myClass,这句话代表myClass的超类型直至Object。
List<Fruit> fruits = new ArrayList<Fruit>();
List<? super Apple> = fruits;
无界通配符
?等价于Object。
(2)泛型方法
之所以声明泛型方法,一般是因为你想要在该方法的多个参数之间宣称一个类型约束。
public <T> T ifThenElse(boolean b, T first, T second) {
return b ? first : second;
}
public 与返回值中间的<T>可以理解为声明此方法为泛型方法。
泛型方法的调用,在方法名前的尖括号中放具体的类型
String middle = ArrayAlg.<String>getMiddle("I'm","ixenos");
大多数情况下,方法调用可以省略<T>,编译器有足够的信息推断出调用的方法,这里利用形参数类型String[]与泛型类型T[]匹配,推断出T是String,故可以调用
String middle = ArrayAlg.getMiddle("I'm","ixenos");
(3)泛型类
在编译器,是无法知道K和V是什么类型,只有在运行时才会真正根据类型来构造和分配内存。
public class Container<K,V>{
private K key;
private V value;
....
}
(4)泛型接口
public interface Generator<T>{
public T text();
}