您的位置:首页 > 编程语言 > Java开发

java高新技术DAY1_反射基础_JDK1.5的新特性_枚举_myeclipse_笔记

2014-03-31 09:59 323 查看
1.5新特性:静态导入;可变参数;增强for循环;自动装箱;枚举......

 

myeclipse笔记

1.显示窗口:window-->Show View

2.配置快捷(模板):window-->Preferences-->General-->Keys-->ContentAssist

3.断点调试:先在对应的行左侧打断点,然后进Debug As(调试界面)

4.Workspace和包的关系,包含多个包,Workspace中的配置影响在其下的所有包

5.Perspective(透视图)View(视图)

6.模板配置:首选项-->Java-->Editor-->Templates

 例:try{$(line_selection/*选定的内容*/)}finally{$(cursor)/*光标

定位处*/}

7.工程导入:先拷贝工程到工作台(可以不),File-import-exists progret...

 工程用的库不同:右键,java build path

8.可变参数相当于有一个数组,故函数内操作时要用数组的方法对其操作

 (int x,int ... args)

9.自动装箱拆箱,Integer i = 10;Integer m = 137;

 两个不同处,如果在一个字节内,即:-128·127就会将对象的引用放到缓

存中,如果数值一样就不在new对象了。如果大于一个字节就不放到缓存中

(享元模式:有很多个小的对象,建立一个对象实体,对象的不同点用方法的参数实

现,称之为外部状态,对象的相同点定义在实体内部,称之为内部状态)

10.枚举:也是一个类;java中枚举的基本调用

public enum WeekDay {
MON,TUE,WED,THS,FRI,SAT,SUN;
}
 

11.枚举中要定义构造方法等,都要放在枚举元素的后面,并且枚举元素后要加;(枚

举中没有定义东西时,可以后面不加分号)

12.枚举的构造必须是私有的

13.枚举元素后面可以加(),括号中放的就是构造方法的参数,默认是空参数()

 这样也就是说枚举中的元素就是本类的对象,是通过空参new出来的

14.枚举复杂型:带上抽象的枚举,--以下为自己理解--也就是本类无法new对象了,

只能通过子类来实现而上面说的枚举中的元素都是对象,那么产生枚举元素的方式也

就变成了匿名子类,通过匿名方式复写父类方法后才能创建对象(这时的对象和刚才枚

 

举的对象是一样的,只不过new的过程比较复杂)

 示例代码:

public enum TrafficLamp {
RED{
public TrafficLamp nextLamp() {
return GREEN;
}

},
GREEN{
public TrafficLamp nextLamp() {
return YELLOW;
}

},
YELLOW{
public TrafficLamp nextLamp() {
return RED;
}

};
public abstract TrafficLamp nextLamp();
}

 

 

15.--自己理解--枚举也可以看成是一种类(和类差不多),但是又和类有不同之处,

类中要是有抽象方法,那么该类也要被abstract修饰,但是枚举不同,枚举可以在其

中有抽象方法时不用被abstract修饰(上面的代码就是)

16.枚举还可以当做单例的一种实现方式,就是枚举中只有一个对象,并将构造方法私有化

***************************

反射:

笔记:

反射:(Reflect)

1.得到一个类的字节码的方式有三种:

 类名.class

 对象.getClass()

 Class.forName("类名")-->这是静态方法

2.得到类的字节码有两中情况:

 

 字节码已经加载到内存中,直接找到字节码并返回即可

 字节码未加载到内存,用类加载器将类加载进内存并把字节码缓存起来用 

forName方式获得加载进来的字节码

3.Class.forName()的作用:返回字节码

而返回字节码的方式有两种

 虚拟机中有(也就是加载过),直接返回即可

 虚拟机中没有,就用类加载器加载,将字节码缓存到虚拟机中,以后要用字

节码就不用再次加载了

4.9个预定义的实例对象(void+8个基本数据类型)

 也就是说void.class();-->这也是一个字节码

5.只要是在源程序中出现的类型都有各自的Class实例对象,比如int[],Array,void

 

6.反射:反射就是把java类中的各种成分反射成相应的java类

7.class类:代表获取一份字节码

8.Constructor类:代表字节码中的一份构造方法

9.Field类:获取字节码中的成员变量

10.Method类:代表获取类字节码中的成员方法

11.用反射方式执行某个类中main方法

12.数组的反射。具有相同的元素类型,相同的维度的每一个数组都属于同一个class

13.Arrays: 数组工具类,提供了许多操作数组的静态方法-->Arrays.asList就是其

中一个,该方法作用是将一个数组转成List集合

14.hashCode的作用:hashSet中就是先用hashCode算出一个值(hashCode的具体算

法不知,好像是用内存算出来的,可以看下图片),存储到对应的存储区域,然后用

equals进行比较(自己理解,也许有出入)

15.hashCode,存储到hashSet中后,不要改已存储的

16.newInstance():是Class中的方法,得到的是一个对象;获得字节码后调用此方

法相当于直接调用该字节码方法()中的参数和该方法参数匹配

17.加载配置文件的三种方法:

 1>.getRealPath();-->获取完整路径

 2>.类名.class.getClassLoader().getResourceAsStream("文件路径+文

件名")获取类加载器,让类加载器加载配置文件(配置文件的存放地点:classPath指

定的目录下,否则类加载器不能加载)(这种加载方式加载的只能读不能写)

 3>.类名.class。getResourceAsStream("文件名")(这种配置文件是用了

相对路径,文件路径是相对于调用的类的包的,所以类加载器可以由包的路径找到文

件,如果文件不是直接放到包下,而是在包下的文件夹或包中,那么就要加上相对于

调用的类所在包的相对路径)

 

反射的基本代码:

package com.xiaofei;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;

public class ReflectText {

public static void main(String[] args) throws Exception{
//111-->获取构造方法
//下面这行代码是用字节码获取到构造方法,可以获取一个构造,也可以获取全部构造,也可以获取指定构造
Constructor<String> constructor = String.class.getConstructor(StringBuffer.class);
//下面是用获取的构造方法产生一个新的对象
String str1 = (String)constructor.newInstance(new StringBuffer("hello"));
//输出
System.out.println(str1);

//222-->获取成员变量
//获取一个公有成员
//new一个Info的对象
Info in = new Info(3,5);
//用Info的字节码获取成员变量(字段),获取到的inf不是变量,而是变量所对应的类字节码中要获取某个对象对应的值
Field infy = in.getClass().getField("y");
//用inf的get方法获取对应对象的值,传的参数in就是那个对应的对象
System.out.println(infy.get(in));

//当用同理获取X的时候,就会报错了,那时因为X是private的,所有获取不到,要获取X怎么办
//用下面这个方法就能获取到私有的变量
//这句就是找到了私有的变量(用上面的方法是找不到私有的),虽然找到了,但是还不能操作
Field infx = in.getClass().getDeclaredField("x");
//进行暴力反射,上面是看到不能操作,这步强行操作
infx.setAccessible(true);
//再用get获取指定对象(in)的值,这样就获取到了X
System.out.println(infx.get(in));

//333-->获取成员变量的综合应用
//获取一个类的成员变量,并将所有的String类型变量中的b替换成a
Info info = new Info(3,5);
Field [] fields = info.getClass().getFields();
for (Field field : fields){
if (field.getType() == String.class){
String oldValue = (String)field.get(info);
String newValue = oldValue.replace("b", "a");
field.set(info, newValue);
}
}
System.out.println(info);

//444--》获取字节码中的成员方法,然后用获取到的方法进行操作
// 下面用反射获取String中的charAt方法,饭后用获取到的方法操作字符串
//直接操作方法:str.charAt(1);
//定义字符串
String str = "abc";
//获取字节码中的成员方法,getMethod中的第一个参数是成员方法名,第二个参数是要获取的方法的参数
Method methodCharAt = String.class.getMethod("charAt", int.class);
//用获取到的方法操作字符串,invoke就是调用方法,下面的第一个参数是调用这个方法的对象,如果为null,表示这个方法是静态的,第二个参数是调用方法传递的参数
System.out.println(methodCharAt.invoke(str, 1));

//555-->用反射方式执行某个类中的main方法
//正常调用: Text.main(new String[]{"111","222","333"});
//要执行哪个类中的main方法,不是在程序中指定的,而是由该类的主函数传递进来的
//下面就是获取该类的main方法传进来的字符串(要执行的类名)
//要在执行时传递给该类main方法参数,传递参数方法-->run as选run Configurations-->Arguments
String stringClassName = args[0];
//有类名获取对应的字节码,然后再获取字节码中的main方法
Method mainMethod = Class.forName(stringClassName).getMethod("main", String[].class);
//用获取到的方法,执行对应的方法,用mainMethod方法调用main
//传参的过程中如果直接传递new String[]{"111","222","333"}会报错,因为main方法会自动将接收到的字符数组拆包,那么参数就成了3为,那么参数列表不匹配了
//为了解决参数列表不匹配的问题,可以用包上加包-->就是用一个字符数组封装这个字符数组,main还在在拆了外层的数组后,参数就剩new String[]{"111","222","333"}了
//mainMethod.invoke(null,new String[]{new String[]{"111","222","333"}});
//将字符数组转成Object 以后main就不会进行拆包操作了
mainMethod.invoke(null,(Object)new String[]{"111","222","333"});

//666-->数组与Object的关系,以及反射类型
//具有相同的元素类型,相同的维度的每一个数组都属于同一个class
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"};

//数组与Object的关系
Object obj1 = a1;		//正确,int[]是Object	-->可以通过字节码获取父类名来知道,String [] 和int [] 的父类是Object,也就是多态,故正确
Object obj2 = a4;		//正确String[]是Object
Object []obj3 = a3;		//正确,int []是Object
Object []obj4 = a4;		//正确,String是Object   -->可以通过字节码获取父类名来知道,String [] 和int [] 的父类是Object,也就是多态,故正确
//Object []obj5 = a2;			//错误,int不是Object---->>>基本数据类型不是Object

System.out.println(a1.getClass() == a2.getClass());		//true-->具有相同的元素类型,相同的维度的每一个数组都属于同一个class
System.out.println(a1.getClass().getSuperclass());		//Object
System.out.println(a4.getClass().getSuperclass());		//Object

//ArraysList-->数组工具类,其中封装了许多的数据常用操作,Arrays.asList()就是其中一个,作用是将数组转换成List集合
//asList方法在1.4版本时接收的是一个Object[]   在1.5版本接收的是泛型可变参数
//int [] 作为参数传递时,int不是Object的,故,传递进去时将int[]作为Object传入,故输出后还是ASCII码
//String[] 作为参数传递时,String是Object的子类,所有传递时将String 数组的每一个元素作为参数传
abf6
递,所有输出的就是String 数组中的元素,而不是ASCII码
System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a4));

//777-->数组的反射应用
//定义数组
Object obj = new int[]{1,2,3};
//获取字节码
Class clazz = obj.getClass();
//isArray()是Class中的一个方法
if (clazz.isArray()){
//getLength(Object obj)是Array中的方法
int len = Array.getLength(obj);
for (int i = 0; i < len ;i++) {
//get是Array中的方法
//System.out.println(Array.get(obj, i));
}
}

//888-->HashSet.HashCode分析  ,以及Hashcode引起的内存泄露
//hashCode只有在使用了这种算法的集合中才有效果,要是存储到ArrayList ,TreeSet集合中的话,就不存在这样的问题
Collection collection = new HashSet();
Info info1 = new Info(3,2);
Info info2 = new Info(3,5);
Info info3 = new Info(3,2);

//hashCode算的是内存区域,因为Info类中复写了HashCode方法,
//所以当两个实参相同时他们就处于同一内存区域中,然后再比较equals方法是否相等
//如果Info中没有复写HashCode方法,HashCode默认是按照内存算的。那么info1和info3HashCode算出来的结果页不同,因为是用内存算的,不是用实参算的

//上面自己总结可能有错

collection.add(info1);
collection.add(info2);
collection.add(info3);
collection.add(info1);

//老师总结:通常来说一个类的两个实例对象用equals方法比较的结果相同时,它们的哈希吗也必须相同,但反之则不成立,即equals方法比较结果不相同的对象可以有相同的哈希吗
//或者说哈希吗相同的两个对象的equals方法的比较结果可以不等,例如:"BB"和"Aa"的equals比较肯定不相等,但是它们的hashcode返回值却相同

//关于HashCode导致的内存泄露问题:老师总结
//内存泄露问题原理:当一个对象被存储进HashSet集合中后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合时的哈希值就
//不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独
//删除当前对象,从而照成了内存泄露

//下面是验证内存泄露的代码
info1.y = 10;
collection.remove(info1);		//结果表明,这步删除并没有操作成功,这就说明内存中有个info1对象,但是已不能单独控制了,造成了泄露

System.out.println(collection.size());

}//mian

}//over


 

 

小知识点:

1.鼠标放在类名上按下F2就会出现完整类名

2.properties 文件的创建:File->file->File name->*.properties即可

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: