您的位置:首页 > 职场人生

黑马程序员—java高新技术_枚举&反射&内省

2014-01-29 22:18 453 查看
----------------------
ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

一、枚举的概念

1、枚举就是要让某个类型的变量的取值只能是若干个固定值中的一个,否则编译会出错。枚举就是让编译器在编译时就可以控制源程序中填写的非法值,普通变量的放式无法实现这一目标。

在JDK1.5之后使用关键字enum定义一种新的类型就是枚举类型。

2、怎么实现枚举功能?

1、将类中的构造方法私有。

2、每个元素分别用一个公有的静态成员变量表示

3、可以有公有方法和抽象函数

4、枚举中所有的方法只能放在元素列表之后

下面是用一般类实现枚举的功能:

public class enumDemo
{
public static void main(String[] args)
{
people p=people.male;
System.out.println(p);
}
}
abstract class people
{
private people(){}
public abstract people done();
public final static people male=new people()
{
public people done()
{
return male;
}
public String toString()
{
return "male";
}

};
public final static people female=new people()
{
public people done()
{
return female;
}
public String toString()
{
return "femal";
}

};
  }


发现用这种方法实现枚举很麻烦。所以java提供了enum这个关键字来定义枚举,实际上就是定义一个类,实现了Enum类而已。所以枚举不能继承别的类,但是可以实现接口。
  public class enumTest
  {
  	public static void main(String[] args)
  	{
  		enumpeople p=enumpeople.man;
  		System.out.println(p);
  		System.out.println(p.name());
  		System.out.println(p.ordinal());//打印对象在枚举中的序列
  		//获取枚举的所有对象
  		enumpeople[] em=enumpeople.values();
  		for(enumpeople enump:em)
  		{
  			System.out.println(enump);
  		}
  	}
  }
   enum enumpeople
  {
  	femal,man//实例对象
  }


2、带构造函数的枚举

  public class enumStudent
  {
  	public static void main(String[] args)
  	{
  		Student s=Student.student1;
  		System.out.println(s);
  	}
  }
  enum Student
  {
  	student1,student2("zhangsan"),student3;
  	private String name;
  	private Student(){
  		System.out.println("调用无参构造函数");
  	}
  	private Student(String name)
  	{
  		this.name=name;
  		System.out.println(name+"调用带参构造函数");
  	}
  }




从结果可以看出student2会调用相应的构造函数。

3、实现抽象方法的枚举

public class eunmAbstract {

public static void main(String[] args)
{
people p=people.male.sex();//调用sex方法
System.out.println(p);
}
}
enum people
{
male{
public people sex()//实现抽象方法
{
return male;
}
},
female{
public people sex()
{
return female;
}
};
private people(){}//构造函数私有化
public abstract people sex();
}


从枚举的特点来看。当枚举只有一个实例对象的时候就是一种单例设计模式的实现方式。

二、反射

反射是在运行状态中。对于任意一个类,都能知道这个类的方法和变量。能调用任意一个类的方法和属性。是动态获取类的信息和调用类的方法

1、反射的基石-->Class类

Class类的对象就是每个类加载到内存后的字节码。

2、一个Java类用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示。

3、获取类的字节码的三种方法:

1.通过该类的对象的getClass()方法获取。这里该类已经被加载到内存了,因为已经有对象的存在。

2.通过类名获取。如String.class;

3.Class.forName(“java.lang.String”)方法。

public class Reflec {

/**
* @param args
*/
public static void main(String[] args)throws Exception {
//创建Class对象方式一
System.out.println("--------创建Class对象---------");
Class personclass=Person.class;
System.out.println(personclass);
//创建Class对象方式二
Person p =new Person();
Class personclass2=p.getClass();
System.out.println(personclass==personclass2);//相同类型的对象得到的字节码文件是同一个
//创建Class对象方式三
Class personclass3=Class.forName("Number26.Person");
System.out.println(personclass==personclass3);//true说明获得//到的是同一份字节码
}
  }

通过上面三种方式我们可以得到一个类的Class对象。那么我们怎么得到类中的构造函数、属性和方法呢?下面逐一介绍

一、Constractor类

     1、调用无参构造函数实例化对象

public static void main(String[] args)throws Exception {

System.out.println("-------------实例化对象-----------");

System.out.println("-----调用无参函数-----");

Person person=(Person)personclass3.newInstance();

System.out.println(person.getAge());//

}

2、调用所有的构造函数

Constractor[] cs=personclass3.getConstractors()

 

3、//取得指定的的构造函数

Constructor cs=personclass3.getConstructor(String.class,int.class);

Person p3=(Person)cs.newInstance("志海",25);

二、获取类信息

获取类名:personclass3.getName()

获取包名:"+personclass3.getPackage().getName()

三、Method类

1、获得所有的方法(包括父类,不包含私有)

Method[] methods=personclass.getMethods();

2、得到私有方法

Method[] methods2=personclass.getDeclaredMethods();

3、调用方法

a) 先获得方法

Method method=personclass3.getMethod("setName", String.class);

 

b) 调用

method.invoke(p3, "唐志海");

调用私有方法:

Method method2=personclass.getDeclaredMethod("show");

method2.setAccessible(true);//忽视访问修饰符

method2.invoke(p3,null);

 

普通调用main方法是:类名.main(new String[]{})

那么我们怎么利用反射来调用main方法吗?

  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  
  public class refluct
  {
  	public static void main(String[] args)
  	{
  		for(String string:args)
  		{
  			System.out.println(string);
  		}
  	}
  
  }
  
  class temple
  {
  	public static void main(String[] args) throws Exception
  	{
  		refluct.main(new String[]{"111","222","333"});
  		//利用反射调用
  		//获得传进来的类名
  		String startclassName=args[0];
  		//找到main方法
  		Method mainthod
  		=Class.forName(startclassName).getMethod("main", String[].class);
  		//调用main方法
  		mainthod.invoke(null,new Object[]{new String[]{"111","222","333"}});
  	}
  }


new Object[]{new String[]{"111","222","333"}}这样把数组封装成object数组是因为,在jdk 1.4中它会把String数组的没个元素都当做参数传给主函数,这样就会造成角标越界异常。在jdk 1.5中可以把一个数组当做一个参数传给main方法。所以为了兼容1.4的版本我们可以把String数组封装成一个Object数组传给main方法。这样就解决了角标越界的异常。

Field类

Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。

Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。

  Field[] filed=personclass3.getFields();
System.out.println(filed.length);
for(Field f:filed)
{
System.out.println(f);
}
Field[] field2=personclass3.getDeclaredFields();//获取私有属性
System.out.println(field2.length);
for(Field f:field2)
{
System.out.println(f.getName());
}

三、内省

内省是对Bean类属性的一种缺省处理方法,探测类内部的一些信息,操作信息。我们可以通过获取javaBean的Bean信息,通过set和get方法操作这些信息。

1、JavaBean

javaBean是一种特殊的java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段。javaBean就是java组件,能被IDE构建工具侦测其属性与方法的能力。javaBean有自己特定的书写规则。就算没有设定属性,我们也可以通过方法的名字得到他的属性名。比如通过setName方法我们可以得到这个javaBean中有个name的属性。

下面就是一个javaBean的书写:

  public class Person
  {
  	private String name;
  	private int age;
  	private void show()
  	{
  		System.out.println("show ::....");
  	}
  	public String getName() {
  		return name;
  	}
  	public void setName(String name) {
  		this.name = name;
  	}
  	public int getAge() {
  		return age;
  	}
  	public void setAge(int age) {
  		this.age = age;
  	}
  	public Person() {
  		super();
  		// TODO Auto-generated constructor stub
  	}
  	public Person(String name, int age) {
  		super();
  		this.name = name;
  		this.age = age;
  	}
  	@Override
  	public String toString() {
  		return "Person [age=" + age + ", name=" + name + "]";
  	}
  
  
  
  }


一个javaBean也可以当做普通类使用,但是作为javaBean用的话就会有很多好处。比说我们要通过getX的方法得到私有的X,会比较麻烦,不过通过内省操作javaBean的话就会简便很多。

 

2、怎么通过内省获取Bean信息?

类 Introspector:

Introspector 将分别分析 bean 的类和超类,寻找显式或隐式信息,使用这些信息构建一个全面描述目标 bean 的 BeanInfo 对象。

(1)BeanInfo getBeanInfo(Class<?> beanClass, int flags)

          在 Java Bean 上进行内省,了解其所有属性、公开的方法和事件,并将结果用一些控制标记表示。

(2)

通过 getPropertyDescriptors()获得 beans PropertyDescriptor。返回的是PropertyDescriptor[];

 

(3)

setReadMethod(Method readMethod)

          设置应该用于读取属性值的方法。

setWriteMethod(Method writeMethod)

          设置应该用于写入属性值的方法。

 

下面就是对上面javaBean操作的事例

  import java.beans.*;
  import java.lang.reflect.*;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.Set;

  import org.apache.commons.beanutils.BeanUtils;
  import org.apache.commons.beanutils.PropertyUtils;

  public class IntrospectorDemo
  {
  	public static void main(String[] args) throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
  	{
  
  		Person p=new Person("zhangsan",14);
  		String name="name";//求name属性的值
  
  		PropertyDescriptor pd=new PropertyDescriptor(name, p.getClass());//得到属性描述
  		System.out.println("-------调用get方法-------");
  
  		Method methodgetName=pd.getReadMethod();//得到getName的方法
  
  		Object value=methodgetName.invoke(p);//调用
  
  		System.out.println("value="+value);
  
  		System.out.println("-------调用set方法-------");
  		Method methodsetName=pd.getWriteMethod();
  		methodsetName.invoke(p,"lisi");
  		System.out.println(p);
  
  		String xx="age";
  
  		PropertyDescriptor pd1=new PropertyDescriptor(xx,p.getClass());
  		Method methodgetAge=pd1.getReadMethod();
  		Object ageValue=methodgetAge.invoke(p);
  		System.out.println("ageValeu="+ageValue);
  
  		System.out.println("-------------内省的另外一种方式-----------");
  		//内省的第二种方式
  		BeanInfo beaninfo=Introspector.getBeanInfo(p.getClass());
  		PropertyDescriptor[] pds=beaninfo.getPropertyDescriptors();
  		for(PropertyDescriptor pd2:pds)
  		{
  			if(pd2.getName().equals(name))
  			{
  				Method method=pd2.getReadMethod();
  				Object value2=method.invoke(p);
  				System.out.println("value2="+value2);
  			}
  		}
  
  
  //BeanUtils更强的功能是直接访问内嵌对象的属性,只要使用点号分隔
  		System.out.println("beanuUtilsGet:"+BeanUtils.getProperty(p, "name"));
  
  		BeanUtils.setProperty(p, "name", "wangwu");
  		System.out.println("BeanUtilsSet:"+p.getName());
  		System.out.println("beanuUtilsGet:"+BeanUtils.getProperty(p, "name").getClass());
  
  
  		PropertyUtils.setProperty(p, xx, 17);
  		System.out.println(p);
  
  
  	}
  
  }


四:总结

好不容易把高新技术视频学完了,第一遍的时候好多真的是感觉糊里糊涂的。想一遍学通真的不是很容易。特点是类加载器和动态代理的时候,第一遍的时候几乎完全听不懂。后面上网查基本概念,看视频,又看了两遍张孝祥老师的视频,现在总算是学会了。虽然两天的视频看了快五天才消化完,不过好歹还是学会了。呼呼~~~~

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

详细请查看:http://edu.csdn.net
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: