泛型
1.在集合类中使用泛型
2.自定义泛型类、泛型方法
3.泛型与继承的关系
4.通配符
一、为什么要有泛型(Generic)?
-
解决元素存储的安全性问题
-
解决获取数据元素时,需要类型强转的问题
泛型,JDK1.5新加入的,解决数据类型的安全性问题,其主要原理是在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在类声明或实例化时只要指定好需要的具体的类型即可。
Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮。二、使用泛型
1.泛型的声明
interface List <T> 和 class TestGen<K,V>
其中,T,K,V不代表值,而是表示类型。这里使用任意字母都可以。常用T表示,是Type的缩写。
2.泛型的实例化:
一定要在类名后面指定类型参数的值(类型)。如:
List<String> strList = new ArrayList<String>();
Iterator<Customer> iterator = customers.iterator();
T只能是类,不能用基本数据类型填充。
2.1 对于泛型类(含集合类)
1.对象实例化时不指定泛型,默认为:Object。
2.泛型不同的引用不能相互赋值。
3.加入集合中的对象类型必须与指定的泛型类型一致。
4.静态方法中不能使用类的泛型。
5.如果泛型类是一个接口或抽象类,则不可创建泛型类的对象。
6.不能在catch中使用泛型
7.从泛型类派生子类,泛型类型需具体化
把一个集合中的内容限制为一个特定的数据类型,这就是generics背后的核心思想。
2.2 自定义泛型类
class Person<T>{
//使用T类型定义变量
private T info;
//使用T类型定义一般方法
public T getInfo(){
return info;
}
public void setInfo(T info){
this.info = info;
}
//使用T类型定义构造器
public Person(){}
public Person(T info){
this.info = info;
}
//static的方法中不能声明泛型
//public static void show(T t){
//}
//不能在try-catch中使用泛型定义
//try{}
//catch(T t){}
}
2.3 对于泛型方法
方法,也可以被泛型化,不管此时定义在其中的类是不是泛型化的。在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。
泛型方法的格式:
[访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常
public class DAO {
public <E> E get(int id, E e){
E result = null;
return result;
}}
2.4 泛型和继承的关系
如果B是A的一个子类型(子类或者子接口),而G是具有泛型声明的类或接口,G并不是G的子类型!
比如:String是Object的子类,但是List并不是List的子类。
public void testGenericAndSubClass() {
Person[] persons = null;
Man[] mans = null;
// 而 Person[] 是 Man[] 的父类.
persons = mans;
Person p = mans[0];
// 在泛型的集合上
List<Person> personList = null;
List<Man> manList = null;
// personList = manList;(报错)
}
2.5 通配符
1.使用类型通配符:?
比如:List<?> ,Map<?,?>
List<?>是List、List等各种泛型List的父类。
2.读取List<?>的对象list中的元素时,永远是安全的,因为不管list的真实类型是什么,它包含的都是Object。
3.写入list中的元素时,不行。因为我们不知道c的元素类型,我们不能向其中添加对象。
唯一的例外是null,它是所有类型的成员。
将任意元素加入到其中不是类型安全的: Collection<?> c = new ArrayList();
c.add(new Object()); // 编译时错误 因为我们不知道c的元素类型,我们不能向其中添加对象。
add方法有类型参数E作为集合的元素类型。我们传给add的任何参数都必须是一个未知类型的子类。因为我们不知道那是什么类型,所以我们无法传任何东西进去。
唯一的例外的是null,它是所有类型的成员。另一方面,我们可以调用get()方法并使用其返回值。返回值是一个未知的类型,但是我们知道,它总是一个Object
package com.atguigu.java;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
/*泛型
* 1.集合类中使用泛型:(没有使用/使用)
* 2.自定义泛型类、泛型方法
* 3.泛型与继承的关系
* 4.通配符:<?>
*
* */
public class TestGeneric {
@Test
public void test3(){
Object obj = new String();
Date d = new Date();
obj = d;
List<Object> list = null;
List<String> list2 = null;
List<?> list3 = null;
//list = list2;
list3 = list;
list3 = list2;
}
@Test
public void Test2(){
List<Integer> list = new ArrayList<Integer>();
//1.实现集合类中元素的添加
list.add(89);
list.add(80);
list.add(87);
//list.add("abc"); //泛型定义的是<Integer>,所以只能添加整型字符
//2.遍历使用了泛型的集合类
Iterator<Integer> iterator = list.iterator();//创建Iterator迭代器
while(iterator.hasNext()){
Integer i = iterator.next();
System.out.println(i);
}
//Map集合类示例:Map<Key,Value>
Map<Integer,String> map = new HashMap<Integer,String>();
map.put(1001, new String("abc"));
map.put(1002, new String("def"));
//map.put(1002,new Date()); //泛型定义的是<Integer,String>,所以new Date()不能添加
//带泛型的Map接口实现类中元素的遍历
Set<Map.Entry<Integer, String>> set= map.entrySet();
for(Map.Entry<Integer, String> entry : set){
System.out.println(entry.getKey() +"------------->"+ entry.getValue());
}
}
@Test
public void Test1(){
ArrayList list = new ArrayList();
list.add(123);
// list.add(new String("abc"));
// list.add(new String("11-11"));
// list.add(new Date());
System.out.println(list.size());
Iterator iterator = list.iterator();
while(iterator.hasNext()){
Integer i = (Integer) iterator.next();
System.out.println(i);
}
}
}
package com.atguigu.java;
import java.util.Collection;
//自定义泛型类
public class Customer<T> {
private T t;
public T getT(){
return t;
}
public void setT(T t){
this.t = t;
}
//从数组到集合的复制
public <T> void copyToCollection(T[] t,Collection<T> coll){
for(T t1:t){
coll.add(t1);
}
}
}
package com.atguigu.java;
import java.util.ArrayList;
import java.util.Collection;
public class TestCustomer {
public static void main(String[] args){
Customer<String> c = new Customer<String>();
c.setT(new String("流氓兔"));
System.out.println(c.getT());
Customer<Integer> c1 = new Customer<Integer>();
c1.setT(12);
System.out.println(c1.getT());
Integer[] i = new Integer[]{1,2,3,4,5};
Collection<Integer> coll = new ArrayList<>();
c.copyToCollection(i, coll);
System.out.println(coll);
}
}
输出结果:
流氓兔
12
[1, 2, 3, 4, 5]
反射
1.理解Class类并实例化Class类对象
2.运行时创建类对象并获取类的完整结构
3.通过反射调用类的指定方法、指定属性
4.动态代理
-
Java Reflection
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的內部信息,并能直接操作任意对象的内部属性及方法
-
Java反射机制提供的功能
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用任意一个对象的成员变量和方法
生成动态代理Java反射机制研究及应用
-
反射相关的主要API:
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造方法
一、Class 类
在Object类中定义了以下的方法,此方法将被所有子类继承:
● public final Class getClass()
以上的方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称。
- 对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE 都为其保留一个不变的 Class
类型的对象。一个 Class 对象包含了特定某个类的有关信息。 - Class本身也是一个类
- Class 对象只能由系统建立对象
- 一个类在 JVM 中只会有一个Class实例
- 一个Class对象对应的是一个加载到JVM中的一个.class文件
- 每个类的实例都会记得自己是由哪个 Class 实例所生成
- 通过Class可以完整地得到一个类中的完整结构
Class类的常用方法
实例
String str = “test4.Person”;
Class clazz = Class.forName(str);
Object obj = clazz.newInstance();
Field field = clazz.getField(“name”);
field.set(obj, “Peter”);
Object obj2 = field.get(obj);
System.out.println(obj2);
注:test4.Person是test4包下的Person类
实例化Class类对象(四种方法)
1)前提:若已知具体的类,通过类的class属性获取,该方法 最为安全可靠,程序性能最高
实例:Class clazz = String.class;
2)前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
实例:Class clazz = “www.atguigu.com”.getClass();
3)前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
实例:Class clazz = Class.forName(“java.lang.String”);
4)其他方式(不做要求)
ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass(“类的全类名”);