Java基础加强<二>_内省、注解、泛型

Java基础加强---day02

五、内省

    JavaBeanJavaBean是一种特殊的Java类,主要用于传递数据信息,这种Java类中的方法主要用于访问私有的字段,并且方法名符合某种命名规则。当某个java类中的一些方法符合某种命名规则,那么就可以把它当做JavaBean来使用。

    如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称为值对象(Value Object)。这些信息在类中用私有字段来存储,如果要读取或者设置这些字段的值,那么需要通过一些相应的方法来访问。

    去掉前缀(set、get)后,剩下的部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改为小写的;如果第二个字母是大写的,第一个字母保留大写。

    总之:一个JavaBean类的属性名可以根据方法名推断出来,并且我们根本看不到java类内部的成员变量

    由于JavaBean广泛的应用性,Eclipse有专门的快捷键产生,即getter和setter。

    JavaBean的好处:

    1、在JavaEE开发中,经常要使用到JavaBean,很多环境要求按照JavaBean,所以JavaBean很重要!

    2、JDK中提供了对JavaBean进行操作的一些API,所以操作相对简单方便,这一套API就称为内省。

    内省:对应的英文单词为:IntroSpector,有内部视察的意思,主要用于对JavaBean的操作。java提供的API为:PropertyDescriptor。但PropertyDescriptor类对JavaBean的操作过于复杂,也可以通过导入BeanUtils工具包对JavaBean进行内省操作。

    万事万物都应该都应该用一个东西来描述,BeanInfo是专门用于描述JavaBean的一个类,也可以通过遍历BeanInfo中所有属性的方式对JavaBean进行描述,IntroSpector.getBeanInfo(<?>class),获取BeanInfo对象。但这种方法操作较为麻烦,可以作为了解。

    导入方式:选中工程,右键-->buildPath-->Configure  buildPath 然后导入相应的工具包,即可。

    产生getter和setter的方式:在类中的空白处,右键-->Source-->Generate  Getters and Setters,然后选中相应字段,即可。

    抽取方法的方式:选中要抽取成为方法的代码,右键-->refactor-->Extract Method,即可。

下面代码体现:

1、内省的演示:

package itheima.day08;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.apache.commons.beanutils.BeanUtils;

import com.sun.xml.internal.fastinfoset.sax.Properties;

import itheima.day07.ReflectPoint;

public class IntroSpectorTest {

	public static void main(String[] args) throws Exception {
		
//		提供设置、获取某个字段的类 就是JavaBean
		ReflectPoint pt1 = new ReflectPoint(3, 5);
		
//		获取读取一个字段的方法
		String propertyName = "x";
		Object returnValue = getProperty(pt1, propertyName);
		System.out.println(returnValue);//3
		
//		设置一个字段的值
		Object value =7;
		setProperty(pt1,propertyName,value);
		
//		使用BeanUtils工具包  
		System.out.println(BeanUtils.getProperty(pt1, "x"));
		
//		BeanUtils工具包的方法更加简便
		
		System.out.println(pt1.getX());//7
		
//		BeanUtils.setProperty(pt1, "birthday.time", "111");//级联操作 
		
//		 System.out.println(BeanUtils.getProperty(pt1, "birthday.time"));  
	}
	
	private static void setProperty(ReflectPoint pt1, String propertyName,
			Object value) throws Exception {
//		PropertyDescriptor(String propertyName, Class<?> beanClass)
		PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pt1.getClass());
		
//		获取set方法 
		Method methodSetX = pd2.getWriteMethod();
		
//		方法关联具体的对象
		methodSetX.invoke(pt1,value);
	}

	private static Object getProperty(Object pt1,String propertyName) throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{

//		操作JavaBean的API,内省
//		PropertyDescriptor(String propertyName, Class<?> beanClass)
		PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1.getClass());
		
//		获取应用于读取字段属性值的方法
		Method methodGetX = pd.getReadMethod();
		
//		关联具体的对象
		Object returnValue = methodGetX.invoke(pt1);
		
//		这是早期的做法
//		BeanInfo类专门用于描述JavaBean
		BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
		
//		获取JavaBean中所有的属性值
		PropertyDescriptor[] pds =beanInfo.getPropertyDescriptors();
		
		Object retvalue =null;
		for(PropertyDescriptor pd1:pds){
//			寻找我们想要的字段名
			if(pd1.getName().equals(propertyName)){
				Method methodGetx1 = pd.getReadMethod();
				retvalue= methodGetx1.invoke(pt1);
			}
		}
		return returnValue;
	}
}

六、注解

    注解:注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记;是注解是JDK1.5的一个重要新特性。

    JDK中自带有三个注解:

    1、@SupressWarning:取消编译器提出的警告,只在源文件时期中有效。

    2、@Deprecated:提示元素是过时的,直到运行期都有效。

    3、@Override:表示覆盖父类中的方法,只在源文件时期有效,只能用在方法上。

    注解相当于程序中要调用的一个类,要在源程序中应用某个注解,得先有这个注解类;好比要调用某个类,必须先开发好这个类。注解的应用结构如下图所示:


    @Retention,元注解,用在注解中的注解,有三个取值:RetetionPolicy.SOURCE、RetetionPolicy.CLASS、RetetionPolicy.RUNTIME;分别对应:java源文件、class文件、内存中的字节码。

    @Target:指示注释类型所适用的程序元素的种类。如果注释类型声明中不存在 Target 元注释,则声明的类型可以用在任一程序元素上。如果存在这样的元注释,则编译器强制实施指定的使用限制。可以是Filed(字段)、Method(方法)、Type(类型,包括类、接口、注解等)。

    注解的属性:注解本身就是给给源程序打上某种标记,则注解的属性就是标记中的标记,即更具体的标记。

下面代码演示:

注解类:

package itheima.day08;

import java.lang.annotation.Retention;
import java.lang.annotation.ElementType;  
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import itheima.day07.EnumTest;

//源注解,指明该注解类的生命周期
@Retention(RetentionPolicy.RUNTIME)

//源注解,指明注解类可以用在什么类型的数据上,即使用目标
@Target({ElementType.METHOD,ElementType.TYPE})

public @interface ItcastAnnotation {
	
//	注解的属性
	String color() default "bule";
	
	String value();
//	 注解的属性有默认值时,应用时可以不必指定
	int[] arrayAttr() default {3,2,1};
	
//	带枚举的注解
	EnumTest.TrafficLamp lam() default EnumTest.TrafficLamp.RED;
}

应用注解的类:

package itheima.day08;

//使用"注解类"的类
//在使用注解类时,必须给未初始化的属性赋值
@ItcastAnnotation(color ="red", value = "abc")
public class AnnotationTest {
	
//	取消警告
	@SuppressWarnings("deprecated")
	
//	只有value一个属性待赋值时,可以省略属性名
	@ItcastAnnotation("xyz")
	
	public static void main(String[] args) {
		
//		过时的方法
		System.runFinalizersOnExit(true);
		
//		MyEclipse提示该方法过时
		AnnotationTest.sayHello();
		
//		对使用注解类的类进行反射
		if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){
			
//			通过反射的形式获取到注解类
			ItcastAnnotation annotation = 
					(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);

//			@itheima.day08.ItcastAnnotation(color=red, lam=RED, arrayAttr=[3, 2, 1], value=abc)
			System.out.println(annotation);
			
//			获取到注解类之后,可以获取注解类中的属性字段
			System.out.println(annotation.color());
			System.out.println(annotation.value());
			System.out.println(annotation.arrayAttr().length); 
			System.out.println(annotation.lam().nextLamp().name());  
		}
		
	}
	
//	给该方法打上过时的标记,使用的是JDK提供的注解类
	@Deprecated
	public static void sayHello(){
		System.out.println("hello itheima");
	}
}

七、泛型

    泛型:泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add方法即可。

    泛型是JDK1.5的一个新特性,没有泛型时,集合中通过Object提供扩展性,但什么类型的对象都可以往同一个集合中放,这就容易引起操作集合中元素时发生一些异常。指定了泛型后,集合中只能放进特定的类型元素,提高了代码的安全性。

    泛型的特定术语:

    ArrayList<E>:泛型类型;E称为类型变量或者类型参数;

   ArrayList<Integer>称为参数化的类型;<>称为typeof;ArrayList称为原始类型。

    参数化类型可以引用一个原始类型的对象,编译报告警告;如:

    Collection<String>c = new Vector();//兼容JDK1.4以前编写的程序;

    原始类型可以引用一个参数化类型的对象,编译报告警告;

    Collectionc = new Vector<String>();//原来的方法接受一个集合参数,新的类型也要能传进去。

    上限:? extends E。

    下限:? super E。

    关于泛型,在集合那一章中有详细的介绍,在此不再赘述!

下面代码演示:

package itheima.day08;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;

public class GenericTest {
	
	public static void main(String[] args) throws Exception {
		
//		在泛型出现之前,用Object提供扩展性
//		面向接口的编程
		Collection collection1 = new ArrayList();
		
//		使用Object提供扩展性,弊端很明显:什么东西都可以往集合中放
		collection1.add(1);
		collection1.add(1.2);
		collection1.add("abc");
		System.out.println(collection1.size());
		
//		JDK1.5版本以后,用泛型限定存入集合的类型
		Collection<String> collection2 = new ArrayList<String>();
		collection2.add("abcd");
		
//		编译通不过,把安全问题扼杀在编译时期
//		collection2.add(1.2);
		System.out.println(collection2.size());
		
//		可以使用反射技术透过编译器
		Constructor<String> constructor1 =
				String.class.getConstructor(StringBuffer.class);
		String str2 = constructor1.newInstance(new StringBuffer("abc"));
		System.out.println(str2);
		
		ArrayList<Integer> collection3 = new ArrayList<Integer>();
		
//		同一份字节码,说明字节码与泛型无关,泛型只是给编译器看门的一个道具,仅此而已
		System.out.println(collection2.getClass()==collection3.getClass());//true
		
//		用反射透过编译器
		collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abc");
		System.out.println(collection3.get(0));
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值