黑马程序员_基础加强(一)

来源:互联网 发布:linux 不能创建目录 编辑:程序博客网 时间:2024/06/13 09:49

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! --------------------

枚举:某个类的对象是确定的,对象的取值只能是确定的对象中的一个。 枚举的构造方法必须是私有的.

枚举的基本应用:

通过enum关键字定义枚举类,枚举类是一个特殊的类,每个元素都是该类的一个实例对象。

用枚举类规定值,如上面的WeekDay类。以后用此类型定义的值只能是这个类中规定好的那些值,若不是这些值,编译器不会通过。

好处:在编译时期就会发现错误,表明值不符合,减少了运行时期的错误。

如果调用者想打印枚举类中元素的信息,需由编写此类的人定义toString方法。

注:枚举类是一个class,而且是一个不可被继承的final类,其中的元素都是类静态常量。

常用方法:

构造器:

        构造器只是在构造枚举值的时候被调用。

        构造器只有私有private,绝不允许有public构造器。这样可以保证外部代码无法重新构造枚举类的实例。因为枚举值是public static final的常量,但是枚举类的方法和数据域是可以被外部访问的。

        构造器可以有多个,调用哪个即初始化相应的值。

非静态方法:(所有的枚举类都继承了Enum方法)

        String toString() ;//返回枚举量的名称

        int ordinal() ;//返回枚举值在枚举类中的顺序,按定义的顺序排

        3Class getClass() ;//获取对应的类名

        4) String name();//返回此枚举常量的名称,在其枚举声明中对其进行声明。

静态方法:

        valueOf(String e) ;//转为对应的枚举对象,即将字符串转为对象

        values() ;//获取所有的枚举对象元素

下面是一个枚举的应用:

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(weekDay2.valueOf("SUN").toString());
System.out.println(weekDay2.values().length);
}
public enum WeekDay{
SUN(1),MON(),TUE,WED,THR,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(40) {
@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;
}

}
}

——————————————————————————————————————

类的反射(不是java1.5的特性):

类Class:描述Java程序中各个Java类的类
在程序运行期间,Java运行时系统始终为所有的对象维护一个
被称之为运行时的类型标识,这个信息保存着每个类所属对象
的类足迹,保存这些信息的类就是Class类
获取Class对象的三种方法:
1.     Class clazz = 类名.class
2.     Class clazz = new 类名().getClass()
3.     Class clazz = Class.forName("类名");

反射:反射就是把Java类中的各个成分映射成相应的Java类,一个类
中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过
调用Class类的方法可以得到这些实例对象

构造方法的反射运用:
1.获取指定类的构造函数(Constructor)
 1.得到某个类(String)所有的构造方法:
  Constructor[] constructors = Class.forName("java.lang.String").getConstructors();
 2.得到某一个构造方法:
  Constructor constructor = Class.forName("java.lang.String").getConstructor("StringBuffer.class");
 3. 创建实例对象
  通常方式:
  String string = new String(new StringBuffer("abc"));
  反射方式:
  String string  = (String)constructor.newInstance(new StringBuffer("abc"));

2.获取指定类的域(Field),也就是成员变量
 1. 得到类的某个成员变量
 Field field = demo.getClass().getField("公有变量名");
 //field 是类上的变量,不是对象的变量,可以用它去取对象上的值
 System.out.println(field.get(demo));//这样才能得到demo对象上y的值
 //这个getField只能得到公有的变量,获取是有的变量的方法
 Field field = demo.getClass().getDeclatredField("私有变量名");
 //要想获得某个对象的私有变量的值,必须使用暴力反射
 field.setAxxessible(true);//使用暴力
 System.out.println(field.get("私有变量所属的对象"));

 3.成员方法的反射(Method):
 1.获取某个类的所有公共成员方法
  Method[] method = demo.getclass().getMethods();
 2.获取某个类的某一个公共成员方法
  Method method = demo.getclass().getMethod("add",int.class);
  //需要指定方法名和方法参数类型的Class对象
  //通过method去调用指定对象的对应的方法
  method.invoke("demo",1);
  //JDK 1.5以后可以使用可变参数列表

数组的反射:
1.具有相同维数和元素类型的数组具有相同的Class实例对象
2.代表数组的Class实例对象的getSuperClass()方法返回的父类
 为Object类对应的Class
3.基本类型的一维数组可以被当做Object类型使用,不能当做Object【】
类型使用,非基本类型的一维数组既可以当做Object类型使用,,
又可以当做Object[]类型使用
反射的作用——>实现框架功能


下面是我对反射的练习代码:

public class ReflectTest {

public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String str = "abc";
Class cls1 = str.getClass(); //获取字节码
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");
System.out.println(cls1 == cls2);
System.out.println(cls1 == cls3);

System.out.println(cls1);//class java.lang.String

System.out.println(cls1.isPrimitive());//不是基本类型
System.out.println(int.class.isPrimitive());
System.out.println(int.class == Integer.class);
System.out.println(int.class == Integer.TYPE);
System.out.println(int[].class.isArray());//数组类型的Class实例对象的方法
//总之,只要是在源程序中出现的类型,都有各自的Class实例对象
// 比如:void,int[]


//new String(new StringBuffer("abc")) 构造函数反射
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
String str2 = (String) constructor1.newInstance(new StringBuffer("abc"));
System.out.println(str2.charAt(2));


ReflectPoint pt1 = new ReflectPoint(3,5);           //这里用到的是下面的JavaBean
Field fieldY = pt1.getClass().getField("y");
//fieldY值是多少?是5,错!fieldY不是对象身上的变量,而是类上,要用它去取某个对象身上的值
System.out.println(fieldY.get(pt1));
Field fieldX = pt1.getClass().getDeclaredField("x");//.getField("x") x是私有的不可见
fieldX.setAccessible(true); //暴力反射
System.out.println(fieldX.get(pt1));

changeStringValue(pt1); //成员反射
System.out.println(pt1);

//str.charAt(2)  //方法反射
Method methodCharAt = String.class.getMethod("charAt", int.class);
System.out.println(methodCharAt.invoke(str, 2)); //如果第一个参数为Null则这是个静态方法
System.out.println(methodCharAt.invoke(str, new Object[]{1}));//new Object[]{new Stirng("abc"),1}



// TestArguments.main(new String[]{"111","222","333"});
String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
//jdk 1.4


int[] a1 = new int[]{1,2,3};
int[] a2 = new int[4];
int[][] a3 = new int[2][3];
String[] a4 = new String[]{"a","b","c"};
System.out.println(a1.getClass() == a2.getClass());
System.out.println(a1.getClass().getName());
System.out.println(a1.getClass().getSuperclass().getName());
System.out.println(a4.getClass().getSuperclass().getName());

Object aObj1 = a1;
Object aObj2 = a4;
// Object[] aObj3 = a1; //错误
Object[] aObj4 = a3;
Object[] aObj5 = a4;


System.out.println(a1);
System.out.println(a4);//地址
System.out.println(Arrays.asList(a1));//[[I@39443f]
System.out.println(Arrays.asList(a4));//[a, b, c]

Object obj = null;
printObject(a1);  //数组的反射
printObject("abc");  
}


private static void printObject(Object obj) {

Class clazz = obj.getClass();
if(clazz.isArray()){
int len = Array.getLength(obj);
for (int i = 0; i < len; i++) {
System.out.print(Array.get(obj, i));
}
}else{
System.out.println(obj);
}
}


private static void changeStringValue(Object obj) throws Exception {
Field[] fields = obj.getClass().getFields();
for(Field field : fields){
// if(field.getType().equals(String.class))
if(field.getType() == String.class){
String oldValue = (String) field.get(obj);
String newValue = oldValue.replace('b', 'a');
field.set(obj, newValue);
}
}

}


}

class TestArguments{
public static void main(String[] args) {
for(String str : args)
System.out.println(str);
}

}

——————————————————————————————————————

首先介绍一下,

JavaBean
        JavaBean是一种用Java语言写成的可重用组件,其实JavaBean就是一个满足一些规则的特殊的Java类。为了写成JavaBean,类必须要满足以下的规则:
1)JavaBean类必须是具体的和公共的,不能是抽象的类或者其它访问权限。
2)必须提供一个无参数的构造方法,可以提供若干有参构造方法,但是此时必须手写一个无参构造方法。
3)JavaBean类中属性最好声明为私有权限,定义setter和getter方法类对属性进行操作。

JavaBean的一些特点:
1)可以实现代码的重复利用
2)易编写、易维护、易使用
3)可以在任何安装了Java运行环境的平台上的使用,而不需要重新编译。

public class ReflectPoint {
private Date birthday = new Date();

private int x;
public int y;

public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "itcast";
public Date getBirthday() {
return birthday;
}

public void setBirthday(Date birthday) {
this.birthday = birthday;
}

public int getX() {
return x;
}

public void setX(int x) {
this.x = x;
}

public int getY() {
return y;
}

public void setY(int y) {
this.y = y;
}

public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}

@Override
public String toString() {
return str1+":"+str2+":"+str3;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((str1 == null) ? 0 : str1.hashCode());
result = prime * result + ((str2 == null) ? 0 : str2.hashCode());
result = prime * result + ((str3 == null) ? 0 : str3.hashCode());
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ReflectPoint other = (ReflectPoint) obj;
if (str1 == null) {
if (other.str1 != null)
return false;
} else if (!str1.equals(other.str1))
return false;
if (str2 == null) {
if (other.str2 != null)
return false;
} else if (!str2.equals(other.str2))
return false;
if (str3 == null) {
if (other.str3 != null)
return false;
} else if (!str3.equals(other.str3))
return false;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}

——————————————————————————————————————

内省:

开发框架时,经常需要使用java对象的属性来封装程序的数据,如果每次通过反射技术来完成这样的操作过于麻烦,所以sun开发了一套API,用于专门操作JavaBean对象的属性。内省(IntroSpector)是Java语言对Bean类属性、事件的一种缺省处理方法。这些API存放在java.beans包下。以上面的名为Pointer的JavaBean类作为例子,对其属性进行操作。
1)通过Introspector类获得Bean对象的 BeanInfo,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应getter/setter 方法,然后通过反射机制来调用这些方法。
Introspector类:
static BeanInfo getBeanInfo(Class<?> beanClass):在JavaBean上进行内省,了解其所有属性、公开的方法和事件。 
BeanInfo接口:
MethodDescriptor[] getMethodDescriptors():获取属性信息,返回一个方法描述器的数组。 
PropertyDescriptor[] getPropertyDescriptors():获取属性信息,返回一个属性描述器的数组。

2)通过PropertyDescriptor来操作Bean对象(java.beans.PropertyDescriptor)
构造方法:
PropertyDescriptor(String propertyName, Class<?> beanClass):通过调用 getFoo 和 setFoo 存取方法,为符合标准 Java 约定的属性构造一个 PropertyDescriptor。
PropertyDescriptor(String propertyName, Class<?> beanClass, String readMethodName, String writeMethodName):此构造方法带有一个简单属性的名称和用于读写属性的方法名称。
PropertyDescriptor(String propertyName, Method readMethod, Method writeMethod):此构造方法带有某一简单属性的名称,以及用来读取和写入属性的 Method 对象。
常用方法:
boolean equals(Object obj):将此 PropertyDescriptor 与指定对象进行比较。 
Class<?> getPropertyType():获得属性的 Class 对象。 
Method getReadMethod():获得应该用于读取属性值的方法。 
Method getWriteMethod():获得应该用于写入属性值的方法。 
void setReadMethod(Method readMethod):设置应该用于读取属性值的方法。 
void setWriteMethod(Method writeMethod):设置应该用于写入属性值的方法。 

 由上述可看出,内省操作非常的繁琐,所以所以Apache开发了一套简单、易用的API来操作Bean的属性——BeanUtils工具包。
BeanUtils工具包:下载:http://commons.apache.org/beanutils/ 注意:应用的时候还需要一个logging包 http://commons.apache.org/logging/下载完成后,将BeanUtils工具包和日志文件全部解压,并导入到当前工程下,就可以使用该工具包了。
步骤:1)在当前工程下右键单击——>新建文件夹——>文件夹取名为lib
            2)解压得到commons-beanutils-1.8.3.jar和commons-logging-1.1.3.jar两个文件都复制黏贴到lib目录下。
            3)在导入的文件下,右键单击——>构建路径——>添加至构建路径——>完成

static String getProperty(Object bean, String name):获取属性值,参数是bean对象和属性名。
static void setProperty(Object bean, String name, Object value):设置属性,参数是字符串或基本类型自动包装。
BeanUtils的特点:
1)对基本数据类型的属性的操作:在WEB开发、使用中,录入和显示时,值会被转换成字符串,但底层运算用的是基本类型,这些类型转到动作由BeanUtils自动完成。
2)对引用数据类型的属性的操作:首先在类中必须有对象,不能是null,例如,private Date birthday=new Date();。操作的是对象的属性而不是整个对象,例如,BeanUtils.setProperty(userInfo,"birthday.time",111111); 

注意:BeanUtils操作只能是属性,不能是对象,上述的birthday是Date的一个对象,通过API发现Date对象下有个setTime(long time)方法, 可以判定Date对象有个time的属性,所以BeanUtils应该操作这个属性,即birthday.time。

下面是内省的代码:

public class IntroSpectorTest {
/**
* @param args
* @throws Exception 
*/
//   内省IntroSpector-->JavaBean-->特殊的Java类
// 为了一些额外的好处
public static void main(String[] args) throws Exception {

ReflectPoint pt1 = new ReflectPoint(3, 5);

String propertyName = "x";

Object retVal = getProperty(pt1, propertyName);

System.out.println(retVal);

Object value = 7;
//setProperty
setProperty(pt1, propertyName,value);

System.out.println(BeanUtils.getProperty(pt1,"x").getClass());
BeanUtils.setProperty(pt1,"x","9");
System.out.println(pt1.getX());
/*
//java7的新特性
Map map = {name:"zxx",age:18};
BeanUtils.setProperty(map, "name", "lhm");
*/
BeanUtils.setProperty(pt1,"birthday.time","111");
System.out.println(BeanUtils.getProperty(pt1,"birthday.time"));

PropertyUtils.setProperty(pt1, "x", 9);
System.out.println(PropertyUtils.getProperty(pt1, "x").getClass());
}
private static void setProperty(ReflectPoint pt1, String propertyName,Object value)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
PropertyDescriptor pd2 = new PropertyDescriptor(propertyName, pt1.getClass());
Method methodSetX = pd2.getWriteMethod();
methodSetX.invoke(pt1,value);
}

private static Object getProperty(ReflectPoint pt1, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
/* //用反射  简单内省操作
PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1.getClass());
Method methodGetX = pd.getReadMethod();
Object retVal = methodGetX.invoke(pt1);
return retVal;
*/

//复杂内省操作
BeanInfo BeanInfo = Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] pds = BeanInfo.getPropertyDescriptors();
Object retVal = null;
for(PropertyDescriptor pd : pds){
if(pd.getName().equals(propertyName)){
Method methodGetX = pd.getReadMethod();
retVal = methodGetX.invoke(pt1);
break;
}
}
return retVal;
}
}


----------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! -------------------

0 0
原创粉丝点击