内省(Introspector):主要对javaBean进行操作。
javaBean:是特殊的java类,类中的方法的名称以get或set打头的类。
可以将javaBean当初普通的类来操作,但是不可以将普通类当javaBean来操作。
一个类被当做javaBean使用时,javaBean的属性是根据方法名推断出来的,去掉set或者get前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。
在Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作。
JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省,用内省这套API操作JavaBean比用普通类的方式更方便。
对javaBean简单的内省操作:使用PropertyDescriptor类
PropertyDescriptor pd = new PropertyDescriptor(propertyName, beanClass);
pd对象上有getReadMethod()和getWriteMethod()返回一个Method,然后可以通过反射使用此方法,具体见下面例子。
对javaBean的复杂内省操作:使用BeanInfo接口
因为BeanInfo是接口,所以不能直接new对象,需要通过Introspector的静态方法getBeanInfo()方法来获得
BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
beanInfo里面提供了getPropertyDescriptors()方法,返回PropertyDescriptor集合。
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
代码示例:
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
public class IntroSpector {
public static void main(String[] args) throws Exception{
ReflectPoint pt1 = new ReflectPoint(3, 5);
String propertyName = "x";
PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1.getClass());
Method methodGetX1 = pd.getReadMethod();
Object retVal1 = methodGetX1.invoke(pt1);
System.out.println(retVal1);
Method methodSetX = pd.getWriteMethod();
methodSetX.invoke(pt1, 7);
System.out.println(pt1.getX());
// 内省的复杂操作方法
BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
Object retVal = null;
for(PropertyDescriptor pd1 : pds){
if(pd1.getName().equals(propertyName)){
Method methodGetX = pd.getReadMethod();
retVal = methodGetX.invoke(pt1);
break;
}
}
System.out.println(retVal);
}
}
BeanUtils工具包的运用:
使用需要在工程下加入jar包,步骤如下:
1.在当前工程上右键New-->Folder(这个文件夹的名字以lib为好,阅读性强)
2.将jar包粘贴到lib目录下
3.将jar包加入到Build Path(jar包上右键选Build Path --》add to Build Path)
图标变成小奶瓶就成功了
方法:BeanUtils中的常用方法。
BeanUtils.getProperty(Object pbj,String PropertyName)
BeanUtils.setProperty(Object pbj,String PropertyName,Object value)
BeanUtils处理属性的时候是以字符串的方式来处理的。设值或者取值都是以字符串来处理的。
枚举:
枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。
枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
注意事项:
1.枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。
2.构造方法必须私有。
3.当枚举只有一个成员时可以作为一种单例的实现模式。
枚举中常用方法和带有构造方法的枚举.
public class EnumTest {
public static void main(String[] args) {
WeekDay weekday2 = WeekDay.FRI;
System.out.println(weekday2);
System.out.println(weekday2.name());
System.out.println(weekday2.ordinal());//排行
System.out.println(WeekDay.valueOf("SUN"));//将字符串SUN转换成WeekDay对象
System.out.println(WeekDay.values().length);//values()返回一个包含所有枚举元素的数组。
}
public enum WeekDay{
//元素列表必须放在最前面,构造方法必须是私有的。Mon()和Mon的效果是相同的都是调用默认的构造方法
SUN(1),MON(),TUE,WED,THI,FRI,SAT;
private WeekDay(){System.out.println("first");}
private WeekDay(int day){System.out.println("second");}
}
public enum TrafficLamp{
RED(30){
@Override
public TrafficLamp nextLamp() {
// TODO Auto-generated method stub
return GREEN;
}
},
GREEN(45){
@Override
public TrafficLamp nextLamp() {
// TODO Auto-generated method stub
return YELLOW;
}
},
YELLOW(5){
@Override
public TrafficLamp nextLamp() {
// TODO Auto-generated method stub
return RED;
}
};
public abstract TrafficLamp nextLamp();
private int time;
private TrafficLamp(int time){this.time = time;}
}
}
小知识点:new Date(300){}new Date的子类对象,调用父类指定的构造方法。
----------------------------------------------------------------------------------------------------------------------------------
静态导入:
静态导入,其实导入的是类中的静态成员。
import语句可以导入一个类或某个包中的所有类,import static语句导入一个类中的某个静态方法或所有静态方法
例:import static java.util.Collections.*;
注意:jdk1.4之前不支持,jdk1.5的新特性。
代码示例:
import static java.lang.Math.max;
public class StaticImport {
public static void main(String[] args) {
System.out.println(max(3, 6));
System.out.println(Math.abs(3 - 6));
}
}
----------------------------------------------------------------------------------------------------------------------------------
函数的可变参数:
特点:
1.只能出现在参数列表的最后。
2. ...位于变量类型和变量名之间。前后有无空格都可以。
3.调用可变参数的方法时,编译器会为该可变参数隐含创建一个数组,
在方法体中以数组的形式访问可变参数。
代码示例:
public static int add(int x,int... args){
int sum = x;
for (int i = 0; i < args.length; i++) {
sum += args[i];
}
return sum;
}
----------------------------------------------------------------------------------------------------------------------------------
增强for循环:
语法:for(type 变量名:集合或者数组){...code...}
注意:此集合或者数组必须实现Iterable接口的类型,Map集合不能直接使用。
public class EnhanceFor {
public static void main(String[] args) {
String[] strs = {"abc","def","ghi"};
for (String str : strs) {
System.out.println(str);
}
}
}
高级for和传统for的区别。
传统for可以完成对语句执行很多次,可以定义控制循环的增量和条件。
高级for是简化形式,必须有被遍历的目标。该目标要么是数组,要么是Collection单列集合。
对于数组的遍历,如果仅仅是获取数组中的元素,可以使用高级For。
如果要对数组的角标进行操作建议使用传统for。
----------------------------------------------------------------------------------------------------------------------------------
基本数据类型的自动拆箱与装箱
涉及的知识点:
享元设计模式:flyweight
很多个小的对象,有很多属性相同,把他们变成一个对象,不同的属性变成方法的参数,
称之为外部状态,相同的属性称之为内部状态。
例:
Integer i1 = 12;//自动装箱
Integer i1 = 12;
System.out.println(num1 + 10)//22 自动拆箱
System.out.println(i1 == i2);//true
//在-128--127;这个范围内为true
Integer i3 = Integer.valueOf(3);//调用静态方法将整数3转成Integer对象。
Integer i4 = Integer.valueOf(3);
System.out.println(i3 == i4);//true
Integer i5 = Integer.valueOf('a');
Integer i6 = Integer.valueOf(97);
System.out.println(i3==i4);//true