---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------
摘要(静态导入---可变参数----高级FOR循环---自动装箱(拆箱)----枚举----反射
小体会:高新技术这里,个人感觉挺难的,首先 eclipse 之前没用过
其次和毕老师的教程联系不太多,第一次看的迷迷糊糊的
直到第二遍才有点感觉, 尤其是反射的原理想了很久才有点明白。
静态导入: import static java........(可以导入包中的静态方法,实现代码简化书写)
|--import语句可以导入一个类或某个包中的所有类
|--import static语句导入一个类中的某个静态方法或所有静态方法
语法举例:
|-- import static java.lang.Math.sin;
自动装箱:把基本数据类型int,自动转换为对象Integer
自动拆箱:把integer自动转为基本数据类型int
Integer num1 = 12;自动拆箱:
System.out.println(num1 + 12);
基本数据类型的对象缓存:
Integer num1 = 12;
Integer num2 = 12; 这块相等,
System.out.println(num1 == num2);
Integer num3 = 129; 这块不相等
Integer num4 = 129;
System.out.println(num3 == num4);
Integer num5 = Integer.valueOf(12);
Integer num6 = Integer.valueOf(12) ;
System.out.println(num5 == num6);
枚举
枚举类的实例对象个数是有限的,就是那些成员,可以在枚举类的构造方法中加入监控语句,看到这几个实例对象被创建出来的过程。
如果想在一个类中编写完各个枚举类和测试调用类,那么可以将枚举类定义成调用类的内部类。
实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,这些子类采用类似内部类的方式进行定义。增加上表示时间的构造方法
枚举只有一个成员时,就可以作为一种单例的实现方式。
讲构造方法枚举时,最好是定义一个带参数的构造方法和一个不带参数的构造方法,问大家默认调用的是哪个构造方法,然后提问想选择带参数的构造方法,该如何做呢?
如果枚举元素后面没有大括号对,那是不会生成内部类的。先看有内部类的效果,再看没有内部类的效果,eclipse自动删除原来的内部类。
写带有抽象方法的枚举步骤和技巧:
1. enum TrafficLamp{RED,GREEN,YELLOW}
2. enum TrafficLamp{RED,GREEN,YELLOW;public abstract next();}
3.enum TrafficLamp{RED{},GREEN{},YELLOW{};public abstract next();}
4.填充各个{}中的next方法。
反射
importjava.lang.reflect.*;
importjava.util.Arrays;
public class ReflectTest {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
String str = "hello";
//获取String类的字节码,三种方法:
Class cls1= String.class;
Class cls2= str.getClass();
Class cls3= Class.forName("java.lang.String");
System.out.println(cls1==cls2);//true
System.out.println(cls1==cls3);//true
System.out.println(cls1.isPrimitive());//false
System.out.println(int.class.isPrimitive());//true
System.out.println(int[].class.isPrimitive());//false
System.out.println(int[].class.isArray());//true
System.out.println(int.class == Integer.class);//flase
System.out.println(int.class == Integer.TYPE);//true
//获取构造器并构造对象
//获取对应类的构造方法,根据参数的不同来指定不同的构造方法
Constructor<String> constr = String.class.getConstructor(StringBuffer.class);
String string =constr.newInstance(new StringBuffer("abc"));
//如果需要调用无参构造方法,可以使用Class.newInstance();
System.out.println(string);
//反射:获取对象的成员变量
ReflectPoint r = new ReflectPoint(3,5);
//getDeclaredField取出声明过的变量,包括public和private
Field fy = r.getClass().getDeclaredField("y");
System.out.println(fy.get(r));
Field fx = r.getClass().getDeclaredField("x");
fx.setAccessible(true);//暴力反射,将private成员设置成可见,才能被get获取
System.out.println(fx.get(r));
changeStringValue(r);
System.out.println(r);
//反射:获取对象的成员方法
Method sumMethod = r.getClass().getMethod("getSum",int.class,int.class);
//调用r对象的getSum方法,并且如果该方法是static的,参数可以是null
//sumMethod.invoke(null,6,7);
//参数类型不确定的情况,可以使用Object数组:sumMethod.invoke(r,new Object[]{每个参数的值});
int sum = (Integer)sumMethod.invoke(r,6,7);
System.out.println(sum);
-
//反射:调用另一个类的main函数(类的静态方法)
//即:对接收数组参数的成员方法进行反射
//需要先设置运行对话框里先设置program argument的值(完整类名)
String startClassName = args[0];
Method mainMethod = Class.forName(startClassName).getMethod(
"main", String[].class);
//当String数组传入时会被拆包,因此需要使用new Object[]{String[]}
//或者(Object)强制转换,阻止对该数组的拆包。
System.out.println(mainMethod.invoke(null,
new Object[]{new String[]{"111","222","333"}}));
System.out.println(a1.getClass().getSuperclass().getName());
System.out.println(a4.getClass().getSuperclass().getName());
Object obj1 =a1;
Object obj2 =a4;
//Object[] obj3 = a1;//编译失败,因为al里装的是int元而不是Object对象
Object[] obj4 = a3;
Object[] obj5 = a4;
//Arrays.asList(Object[] obj),而int是元数组而不是对象数组,因此不符合参数条件
System.out.println(Arrays.asList(a1));//hash值
System.out.println(Arrays.asList(a4));//元素值
//数组的反射
//当有一个Object数组,元素值类型不一,就需要用到反射来取元素及元素类型
printArray(a4);
}
public static void printArray(Object obj){
Class class_ex = obj.getClass();
if(class_ex.isArray()) {
int len = Array.getLength(obj);
for (int i = 0; i < len; i++) {
System.out.println(Array.get(obj,i));
}
} else {
System.out.println(obj);
}
}
public static void changeStringValue(Object obj)throws Exception{
Field[] fields = obj.getClass().getFields();
for (Field field : fields) {
if(field.getType()==(String.class)) {
String newstr = field.get(obj).toString().replaceAll("b","a");
//将obj对象的field字段设置成newstr
field.set(obj,newstr);
}
}
}
}
class TestArgument{
public static void main(String[] args){
for (String string : args) {
System.out.println(string);
}
}
}
public class ReflectPoint {
private int x;
public int y;
public String str1="ball";
public String str2="baseball";
public String str3="itcast";
publicReflectPoint(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString(){
return "x= "+x+" ;y= "+y+"\n"+"str1= "+str1+"" +
" ;str2= "+str2+" ;str3= "+str3;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
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 (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
public int getSum(int a,int b){
return a+b;
}
}
HashCode与内存泄露
import java.util.*;
public class ReflectTest2 {
public static void main(String[] args){
Collection coll = new HashSet();
ReflectPoint r1 = new ReflectPoint(3,3);
ReflectPoint r2 = new ReflectPoint(5,5);
ReflectPoint r3 = new ReflectPoint(3,3);
coll.add(r1);
coll.add(r2);
coll.add(r3);//覆盖了HashCode方法和equals方法,因此视为与r1相同元素
coll.add(r1);
System.out.println(coll.size());//2
r1.y=2;
coll.remove(r1);
System.out.println(coll.size());//2
//原因是:当涉及到HashCode值的字段发生了改变,那么再去搜索就找不到原来
//对应的HashCode的元素了,但是程序员察觉不到,就造成了内存泄露。
}
}
import java.io.*;
import java.util.*;
/ *利用反射技术使用运行时的类,反射技术开发框架原理 * /
public class ReflectTest2 {
public static void main(String[] args) throws Exception{
//一定要记住用完整的路径,但完整的路径不是硬编码。而是通过运算得出来的。
//InputStream in = new FileInputStream("config.properties");
//使用类加载器的方式管理配置和资源文件。
//InputStream in = ReflectTest2.class.getClassLoader().getResourceAsStream("cn\\itcast\\day2\\config.properties");
//相对主类所在的包的相对路径
InputStream in = ReflectTest2.class.getResourceAsStream("config.properties");
//如果是放在cn.itcast.resource包里,则就要使用该包的相对路径"resourse\\config.properties"
//因此,资源文件一般放在eclipse的src目录或者子目录下。
Properties props = new Properties();
props.load(in);
String className = props.getProperty("className");
//要将泛型实例指定为Collection对象
Collection coll = (Collection)Class.forName(className).newInstance();
coll.add("java01");
coll.add("java02");
coll.add("java03");
coll.add("java01");
System.out.println(coll.toString());
}
}
JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。
如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,大家觉得这些方法的名称叫什么好呢?JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id,至于你把它存到哪个变量上,用管吗?如果方法名为getId,中文意思即为获取id,至于你从哪个变量上取,用管吗?去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;;
/ *内省的简单应用方式* /
public class IntroSpectorTest1 {
public static void main(String[] args) throws Exception{
ReflectPoint rp = new ReflectPoint(3,5);
//利用给定的属性名对getter和setter进行调用
//利用PropertyDescriptor设置属性描述,构造方法参数为属性名及所在类
String prop = "x";
PropertyDescriptor pd = new PropertyDescriptor(prop,rp.getClass());
//以下get/setProperty方法利用Refactor进行重构,导出方法-->Extract methood
Object retValue = getProperty(rp, pd);
System.out.println(retValue);
Object setValue = 7;
setProperty(rp, pd, setValue);
System.out.println(getProperty(rp,pd));
}
/ *PropertyDescriptor的getReadMethod以及getWriteMethod方法返回一个Method类型对象
/ *需要用invoke方法进行对应setter getter方法的调用
** /
public static void setProperty(Object rp, PropertyDescriptor pd,
Object setValue) throws IllegalAccessException,
InvocationTargetException {
Method setMethod = pd.getWriteMethod();
setMethod.invoke(rp, setValue);
}
public static Object getProperty(Object rp, PropertyDescriptor pd)
throws IllegalAccessException, InvocationTargetException {
Method getMethod = pd.getReadMethod();
Object retValue = getMethod.invoke(rp);
return retValue;
}
}
/ *使用BeanInfo方法
*
* * /
public static Object getProperty(Object rp, String prop)
throws IllegalAccessException, InvocationTargetException, IntrospectionException {
BeanInfo beanInfo = Introspector.getBeanInfo(rp.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
Object refValue = null;;
for (PropertyDescriptor pd_x : pds) {
if (pd_x.getName().equals(prop)) {
Method getMethod = pd_x.getReadMethod();
refValue = getMethod.invoke(rp);
break;
}
}
return refValue;
}
在前面内省例子的基础上,用BeanUtils类先get原来设置好的属性,再将其set为一个新值。
get属性时返回的结果为字符串,set属性时可以接受任意类型的对象,通常使用字符串。
用PropertyUtils类先get原来设置好的属性,再将其set为一个新值。
去掉JavaBean(ReflectPoint)的public修饰符时,BeanUtils工具包访问javabean属性时出现的问题。
/ *使用BeanUtils方法(自己下载包:beanutils和logging):
* System.out.println(BeanUtils.getProperty(rp,prop));
* BeanUtils.setProperty(rp,prop,"9"); //以String类型进行设置
* System.out.println(BeanUtils.getProperty(rp,prop));
*
* 当存在对象类型的属性:private Date birthday = new Date();
* 则需要用属性链进行设置,用属性链进行查看
* BeanUtils.setProperty(rp,"birthday.time","12000");
* System.out.println(BeanUtils.getProperty(rp,"birthday.time"));
*
* BeanUtils是以字符串String类型对属性值进行操作,PropertyUtils是以属性值本身类型进行操作
* PropertyUtils.setProperty(rp,prop,9);
* System.out.println(BeanUtils.getProperty(rp,prop));
* //返回Integer值
*
* java7的新特性:Map定义
* Map map = {name:"yun",age:20};
* 通过describe和populate两个方法,在bean对象和map对象时间进行转换。
* * /
定义一个最简单的注解:public @interface MyAnnotation {}
把它加在某个类上:@MyAnnotation public class AnnotationTest{}
用反射进行测试AnnotationTest的定义上是否有@MyAnnotation
根据反射测试的问题,引出@Retention元注解,其三种取值:RetetionPolicy.SOURCE、RetetionPolicy.CLASS、RetetionPolicy.RUNTIME;分别对应:
java源文件-->class文件-->内存中的字节码。
思考:@Override、@SuppressWarnings和@Deprecated这三个注解的属性值分别是什么?(SOURCE、SOURCE、RUNTIME)
@Target元注解
Target的默认值为任何元素。
设置Target等于ElementType.METHOD,原来加在类上的注解就报错了,改为用数组方式设置{ElementType.METHOD,ElementType.TYPE}就可以了。
元注解以及其枚举属性值不用记,只要会看jdk提供那几个基本注解的API帮助文档的定义或其源代码,按图索骥即可查到,或者直接看java.lang.annotation包下面的类。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
importjava.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/ *使用元注解对自定义注解进行标注
* RetentionPolicy是一个枚举类,有三个 枚举值常量SOURCE CLASS RUNTIME
* * /
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE}) //表示任意类型的元素,不一定是注解在方法上
public @interface MyAnnotation {
}
import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Annotation;
@MyAnnotation
public class AnnotationTest {
public static void main(String[] args) {
if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)){
MyAnnotation myAnn = (MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(myAnn);
}
}
}
Class类实现了该接口,并且如Enum、interface、@interface等,虽然不属于Class类,但都是java中的一种类型,因此都实现了接口Type。该接口的概念更宽泛。
@MyAnnotation(color="red")
用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法
MyAnnotation aØ = (MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(a.color());
可以认为上面这个@MyAnnotation是MyAnnotaion类的一个实例对象
为属性指定缺省值:
String color() default "yellow";
value属性:
String value() default "zxx";
数组类型的属性
int [] arrayAttr() default {1,2,3};
@MyAnnotation(arrayAttr={2,3,4})
如果数组属性中只有一个元素,这时候属性值部分可以省略大括号
枚举类型的属性
EnumTest.TrafficLamp lamp() ;
@MyAnnotation(lamp=EnumTest.TrafficLamp.GREEN)
注解类型的属性:
MetaAnnotation annotationAttr() default @MetaAnnotation("xxxx");
@MyAnnotation(annotationAttr=@MetaAnnotation(“yyy”) )
可以认为上面这个@MyAnnotation是MyAnnotaion类的一个实例对象,同样的道理,可以认为上面这个@MetaAnnotation是MetaAnnotation类的一个实例对象,调用代码如下:
MetaAnnotation ma = myAnnotation.annotationAttr();
System.out.println(ma.value());
注解的详细语法可以通过看java语言规范了解,即看java的language specification。
---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------