Java期末复习速成(八)

Java期末复习速成(八)


泛型



在Jdk1.5中,提出了一种新的概念,那就是泛型,那么什么是泛型呢?

泛型其实就是一种参数化的集合,它限制了你添加进集合的类型。泛型的本质就是一种参数化类型。多态也可以看作是泛型的机制。一个类继承了父类,那么就能通过它的父类找到对应的子类,但是不能通过其他类来找到具体要找的这个类。泛型的设计之处就是希望对象或方法具有最广泛的表达能力。

下面来看一个例子说明没有泛型的用法

List arrayList = new ArrayList();
arrayList.add( "cxuan");
arrayList.add(100);

for(int i=0; i<arrayList.size();i++){
	String item = (String)arrayList.get(i);
	System.out.println("test === ", item);
}

这段程序不能正常运行,原因是Integer类型不能直接强制转换为String类型

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

如果我们用泛型进行改写后,示例代码如下

List<String arrayList = new ArrayList<String>();
arrayList.add(100);

这段代码在编译期间就会报错,编译器会在编译阶段就能够帮我们发现类似这样的问题。

泛型的使用

泛型的使用有多种方式,下面我们就来一起探讨一下。

用泛型表示类

泛型可以加到类上面,来表示这个类的类型

//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
public class GenericDemo<T>{
	//value这个成员变量的类型为T,T的类型由外部指定
	private T value;
	
	public GenericDemo(T value) {
		this. value = value;
	}
	
	public T getValue(){ 		//泛型方法getKey的返回值类型为T,T的类型由外部指定
		return value;
	}
	
	public void setValue(T value){
		this.value = value;
	}
}

用泛型表示接口

泛型接口与泛型类的定义及使用基本相同。

//定义一个泛型接口
public interface Generator<T> {
	public T next();
}

一般泛型接口常用于 生成器(generator) 中,生成器相当于对象工厂,是一种专门用来创建对象的类。

泛型方法

可以使用泛型来表示方法

public class GenericMethods {
	public <T> void f(T x){
		System.out.println(x.getClass().getName());
	}
}

泛型通配符

List是泛型类,为了表示各种泛型List 的父类,可以使用类型通配符,类型通配符使用 问号(?) 表示,它的元素类型可以匹配任何类型。例如

public static void main(String[] args) {
	List<String> name = new ArrayList<String>();
	List<Integer> age = new ArrayList<Integer>();
	List<Number> number = new ArrayList<Number>();
	name.add("cxuan");
	age.add(18);
	number.add(314);
	generic(name) ;
	generic(age);
	generic(number);
}

public static void generic(List<?> data) {
	System. out.println( "Test cxuan :" + data.get(0));
}

上界通配符: <? extends ClassType>该通配符为ClassType 的所有子类型。它表示的是任何类型都是ClassType 类型的子类。

下界通配符: <? super ClassType>该通配符为ClassType的所有超类型。它表示的是任何类型的父类都是ClassType。


反射



反射是Java 中一个非常重要同时也是一个高级特性,基本上Spring等一系列框架都是基于反射的思想写成的。我们首先来认识一下什么反射。

Java反射机制是在程序的运行过程中,对于任何一个类,都能够知道它的所有属性和方法;对于任意一个对象,都能够知道调用它的任意属性和方法,这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。(来源于百度百科)

Java反射机制主要提供了以下这几个功能

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所有的成员变量和方法
  • 在运行时调用任意一个对象的方法

这么一看,反射就像是一个掌控全局的角色,不管你程序怎么运行,我都能够知道你这个类有哪些属性和方法,你这个对象是由谁调用的,嗯,很屌。

在Java中,使用 Java.lang.reflect 包实现了反射机制。Java.lang.reflect所设计的类如下

在这里插入图片描述

下面是一个简单的反射类

public class Person {
	public String name;//姓名
	public int age;//年龄
	
	public Person() {
		super();
	}

	public Person( String name,int age) {
		super();
		this.name = name;
		this.age = age;
	}
	
	public string showInfo() {
		return "name=" +name + ", age=”+age;
	}
}

public class Student extends Person implements Study {
	public string className;//班级
	private string address;//住址

	public student(){
		super();
	}
	
	public student(String name,int age,String className,String address) {
		super(name,age);
		this.className = className;
		this.address = address;
	}
	
	public student(String className) {
		this.className = className;
	}
	
	public string toString() {
		return"姓名: " + name + ",年龄;" + age +",班级: "+ className + ",住址:" +address;
	}

	public String getAddress() {
		return address;
	}
	
	public void setAddress(String address) {
		this.address = address;
	}
}

public class TestRelect {

	public static void main(String[]args) {
	Class student = null;
	try {
		student -=Class.forName( " com. cxuan.reflection.Student");
	}catch (classNotFoundException e) {
		e.printstackTrace();
	}

	//获取对象的所有公有属性
	Field[] fields = student.getFields();
	for (Field f : fields) {
		System. out.println(f);
	}
	System. out.println( "------------")
	//获取对象所有属性,但不包含继承的。
	Field[] declaredFields = student.getDeclaredFields();
	for (Field df : declaredFields) {
		System. out.println(df );
	}
	
	//获取对象的所有公共方法
	Method[]methods = student.getMethods();
	for (Method m : methods) {
		System.out.println(m);
	}
	System. out.println( "---------------------");

	//获取对象所有方法,但不包含继承的
	Method[] declaredMethods = student.getDeclaredMethods();
	for (Method dm : declaredMethods) {
		System.out.println(dm);
	}

	//获取对象所有的公共构造方法
	Constructor[] constructors = student. getConstructors();
	for (constructor c : constructors) {
		System. out.println(c);
	}
	System. out.println( "---------------------");

	//获取对象所有的构造方法
	Constructor[] declaredConstructors = student.getDeclaredConstructors();
	for (constructor dc : declaredConstructors) {
		System. out.println(dc);
	}
	
	Class c = class.forName( "com. cxuan.reflection. Student");
	Student stu1 = (Student) c.newInstance();
	//第一种方法,实例化默认构造方法,调用set赋值
	stu1.setAddress("河北石家庄");
	System. out.println(stu1);
	
	//第二种方法取得全部的构造函数使用构造函数赋值
	Constructor<Student> constructor = c.getConstructor(String.class,int.class,String.class,string.class);
	Student student2 = (Student) constructor .newInstance( " cxuan",24,"六班","石家庄");
	System. out.println(student2);
	
	/**
	*玃取方法并执行方法
	*/
	Method show = c.getMethod("showInfo");//获取showInfo()方法
	object object = show.invoke(stu2);//调用showInfo()方法
	}
}

有一些是比较常用的,有一些是我至今都没见过怎么用的,下面进行一个归类。

与Java反射有关的类主要有

Class类

在Java 中,你每定义一个java class实体都会产生一个 Class对象。也就是说,当我们编写一个类,编译完成后,在生成的**.class**文件中,就会产生一个Class对象,这个Class对象用于表示这个类的类型信息。Class 中没有公共的构造器,也就是说Class对象不能被实例化。下面来简单看一下Class类都包括了哪些方法

toString()

public string toString(){
	return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))+getName();
}

toString() 方法能够将对象转换为字符串,toString() 首先会判断Class类型是否是接口类型,也就是说,普通类和接口都能够用Class对象来表示,然后再判断是否是基本数据类型,这里判断的都是基本数据类型和包装类,还有void 类型。

所有的类型如下

  • java.lang.Boolean :代表boolean数据类型的包装类
  • java.lang.Character:代表char数据类型的包装类
  • java.lang.Byte:代表 byte数据类型的包装类
  • java.lang.Short:代表short 数据类型的包装类
  • java.lang.Integer:代表int数据类型的包装类
  • java.lang.Long:代表long 数据类型的包装类
  • java.lang.Float:代表float 数据类型的包装类
  • java.lang.Double:代表double 数据类型的包装类
  • java.lang.Void:代表void数据类型的包装类

然后是 getName() 方法,这个方法返回类的全限定名称。

  • 如果是引用类型,比如String.class.getName() -> java.lang.String
  • 如果是基本数据类型,byte.class.getName() -> byte
  • 如果是数组类型,new Object[3]).getClass().getName() -> [Ljava.lang.0bject

toGenericString()

这个方法会返回类的全限定名称,而且包括类的修饰符和类型参数信息。

forName()

根据类名获得一个Class对象的引用,这个方法会使类对象进行初始化。
例如 Class t = Class.forName( " java.lang.Thread") 就能够初始化一个Thread 线程对象

在Java 中,一共有三种获取类实例的方式

  • Class.forName(java.lang.Thread)
  • Thread.class
  • thread.getClass()

newlnstance()

创建一个类的实例,代表着这个类的对象。上面forName()方法对类进行初始化,newInstance方法对类进行实例化。

getClassLoader()

获取类加载器对象。

getTypeParameters()

按照声明的顺序获取对象的参数类型信息。

getPackage()

返回类的包

getlnterfaces()

获得当前类实现的类或是接口,可能是有多个,所以返回的是Class数组。

Cast

把对象转换成代表类或是接口的对象

asSubclass(Class clazz)

把传递的类的对象转换成代表其子类的对象

getClasses()

返回一个数组,数组中包含该类中所有公共类和接口类的对象

getDeclaredClasses()

返回一个数组,数组中包含该类中所有类和接口类的对象

getSimpleName()

获得类的名字

getField()

获得所有公有的属性对象

getField(String name)

获得某个公有的属性对象

getDeclaredField(String name)

获得某个属性对象

getDeclaredFields()

获得所有属性对象

getAnnotation(Class annotationClass)

返回该类中与参数类型匹配的公有注解对象

getAnnotations()

返回该类所有的公有注解对象

getDeclaredAnnotation(Class annotationClass)

返回该类中与参数类型匹配的所有注解对象

getDeclaredAnnotations()

返回该类所有的注解对象

getConstructor(Class…<?> parameterTypes)

获得该类中与参数类型匹配的公有构造方法

getConstructors()

获得该类的所有公有构造方法

getDeclaredConstructor(Class…<?> parameterTypes)

获得该类中与参数类型匹配的构造方法

getDeclaredConstructors()

获得该类所有构造方法

getMethod(String name, Class…<?> parameterTypes)

获得该类某个公有的方法

getMethods()

获得该类所有公有的方法

getDeclaredMethod(String name,Glass…<?> parameterTypes)

获得该类某个方法

getDeclaredMethods()

获得该类所有方法


Field类

Field类提供类或接口中单独字段的信息,以及对单独字段的动态访问。

这里就不再对具体的方法进行介绍了,读者有兴趣可以参考官方API

这里只介绍几个常用的方法

equals(Object obj)

属性与obj相等则返回true

get(Object obj)

获得obj中对应的属性值

set(Object obj, Object value)

设置obj中对应属性值


Method类

invoke(Object obj, Object… args)

传递object对象及参数调用该对象对应的方法

ClassLoader类

反射中,还有一个非常重要的类就是ClassLoader类,类装载器是用来把类(class)装载进JVM的。ClassLoader使用的是双亲委托模型来搜索加载类的,这个模型也就是双亲委派模型。

ClassLoader 的类继承图如下

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/ws15168689087/article/details/125125830