IDE:集成开发环境(integrated development environment)
设置在Eclipse中显示输入帮助:window—>Preferences—>General—>Keys:在(从上到下第二个文本框中:type filter text)输入content assist,就可以查看显示输入帮助的快捷键,也可以输入快捷键查看与之相关的服务,以免有不相同的服务用相同的快捷键。修改快捷键:修改下面的Binding选项即可
查看程序中变量的值:选中相关的语句,右击选debug as选项。运行后就切换到Debug透视图下,在代码中选中变量右击点watch选项后,在右上的窗口中即可查看。
修改工程的名字:选中工程点右键选Refactor—>Rename
透视图(perspective)即一系列小窗口的集合,也就是一些视图的集合。
设置workspace(工作台)的javac与java:
设置javac:window—>Preferences—>java—>complier,然后选择相应的版本
设置java:window—>Preferences—>java—>Installed JREs
而设置整个eclipse的java与javac则在window—>Preferences—>General中设置
高版本的java能运行低版本的javac编译的程序,反之低版本的java不能运行高版本javac编译的程序。
某个工程也已覆盖工作台的配置
设置代码模板:window—>Preferences—>java—>Templates,添加的话点new按钮。在Pattern中输入框架如:
try{
${line_selection}//代表被选中的代码,通过点Insert Variablea按钮添加
}finally{
${cursor}//代表光标
}
使用代码模板:选中相应的代码,点右键选Surround with添加。
在eclipse中添加已有的工程:首先将工程文件夹放到相应的workspace下,然后在该workspace下打开eclipse,点File—>import—>General—>Existing Projects into workspace—>select root directory
如果导入的工程所用的jdk与workspace中所用的jdk不同,就选中导入的工程点右键—>build path—>configure build path—>libraries,remove掉原有的JRE,在add新的JRE。如果jar包已经在工程中了,则选择Add JARs,若jar包没在工程中则增加外部的jar包:Add External JARs。我们此处选择Add libraries,增加JRE库。
(java5的新特性)
静态导入
import语句可以导入一个类或某个包中的所有类,所谓导入不占用任何的java资源,只是让我们写java原程序的时候少些一些前缀而已。
静态导入(java 1.5以后提供的)导入类中的静态方法,例如import static java.lang.Math.*,这样我们就可以直接使用:System.out.println(max(3,6));
overload: 重载,override:重写
可变参数(如:int … a):用于一个方法可接受的参数个数不固定的情况。(jdk1.5提供)
特点:只能出现在参数列表的最后;符号“…”位于变量名之间,前后有无空格都可以;调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法中数以组的形式访问可变参数。例如:
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 变量名:集合变量名){…},用变量去逐一取集合中的每一个元素的值,每取一个元素的值,就去执行一次循环体。
注意事项:迭代变量必须在()中定义!集合变量可以是数组或实现了lterable接口的集合类。
举例,可将上面的代码修改为:
public static int add(int x,int ….args){
int sum=x;
for(int arg:args){
sum+=arg;
}
return sum;
}
基本数据类型的自动拆箱与装箱
自动装箱:Integer num1=12;在java5以后允许这样表达,将整数12包装成一个Integer类对象,然后赋值给num1.
自动拆箱: System.out.println(num1+12);由于num1是Integer类型的对象,不能直接进行算术运算,所以此处会将num1拆箱,使之变成一个基本数据类型的数,然后参与运算。
基本数据类型的对象缓存:
Integer num1=12;
Integer num2=12;
Sytem.out.println(num1==num2);
此处的返回值为true。
Integer num3=129;
Integer num4=129;
Sytem.out.println(num3==num4);
此处的返回值为false。
因为对于基本数据类型的整数,如果要装箱成为Integer对象,并且如果这个数值在一个字节之内,即在-128-127之间的时候,把它们包装成Integer对象后,会回把它们缓存在一个池里面。带到下次用的时候就从池子里取,就不需要创建新的对象了,所以第一个返回值为true。较大的整数的使用没有小的整数那样频繁,所以就会产生不同的对象。
享元模式(flyweight)如果很多很小的对象有很多相同的东西,这样就可以编程一个对象,将其他不同的地方变成外部的属性,作为方法的参数传入。
Integer num5=Integer.valueOf(12); //这不是装箱,虽然也可以将12包装成Integer对象。
Integer num6=Integer.valueOf(12);
System.out.println(num5==num6);
返回结果的控制与上面相同。
枚举
使用枚举来规定某变量的值,也就是我们定义了一个新的类型并规定了它的值,以后使用该类型去定义变量时,变量的值就只能是那些已经规定好的值。而每一个枚举元素值都是一个实例对象。
(用抽象方法定义某些方法,就可以将大量的if else语句转移一个独立的实现了抽象方法的各个类中)
枚举的定义及基本的使用:
public enum WeekDay{
//枚举也是一个类,此处WeekDay就是一个类,其中的每一个元素都是它的实例对象。
SUN,MON,TUE,WED,THI,FRI,SAT;
}
WeekDay weekDay2 = WeekDay.FRI; //静态的
System.out.println(weekDay2);
System.out.println(weekDay2.name());
System.out.println(weekDay2.ordinal());
//返回FRI在WeekDay取值中是第几个,从0开始算,应返回5.还有一个getClass方法,因为枚举为一个类,它的值为对象,若调用getClass()方法,应返回WeekDay。
System.out.println(WeekDay.valueOf("SUN").toString());
// WeekDay.valueOf("SUN"):将SUN变为WeekDay的实例对象。
System.out.println(WeekDay.values().length);
// WeekDay.values()返回一个WeekDay类型的数组,数组的值就是WeekDay所能取的值,也就是它的所有对象。便于进行遍历。
枚举中也可有构造方法:
public enum WeekDay{
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,GREEN,YELLOW;
public abstract TrafficLamp nextLamp();
}
因为这个枚举中有抽象方法,所以不能用new来产生新的对象。只能用其子类来产生RED,GREEN,YELLOW等对象。
public enum TrafficLamp{
RED(30){
public TrafficLamp nextLamp(){
return GREEN;
}
},
/*用匿名类产生子类的实例对象(注意:RED本身是对象,所以原理与
newTest(){}同),调用父类(此处为:TrafficLamp)的构造函数*/
GREEN(45){
public TrafficLamp nextLamp(){
return YELLOW;
}
},
YELLOW(5){
public TrafficLamp nextLamp(){
return RED;
}
};
public abstract TrafficLamp nextLamp();
private int time;
private TrafficLamp(int time){this.time = time;}
}
枚举只有一个成员时,就可以作为一种单例的实现方式。
Class类
java类用于描述一类事物的共性,该类事物拥有各种属性。至于这个属性的值是什么,则是有这个类的实例对象来确定的,不同的实例对象有不同的属性值。java程序中的各个java类,也属于同一类事物,也可用一个类来描述,这个类就是Class类。
由于java程序中的类在内存中以字节码的形式存在,所以Class类所对应的实例对象就是这些类相应的字节码,例如:有一个Person类,它的字节码就是Class类的一个对象:
Class cls1= Person.class.另两种获得类的字节码的方式是,用类的实例对象调用getClass方法:Person p1=new Person(); p1. getClass()。或者用Class.forName(“相应类的完整名称(包括包名)”);调用Class.forName有两种情况,一个是相应的类没有加载到内存即java虚拟机中,则需要用类加载器将该类加载到内存中,然后获得相应的字节码;再一个是该类已经在加载到了java虚拟机中,则可直接返回其字节码。
像boolean、byte、char、short、int、long、float、double都分别有对应Class类的实例对象,有:Class cls=int.class;甚至void也是如此:Class cls=void.class。这九个类型是预定义的Class的实例对象。
凡在java程序中出现的类型都有各自的Class实例对象,都可以通过.calss来获得。
反射(注意:先获得类的字节码)
反射就是把java类中的各种成分映射成相应的java类。就是将一个类中各个成份转换成一个个类。例如,一个java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等信息也用一个个的java类相应的对象来表示,就像汽车是一个类,汽车中的发动机,变速箱等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,这些相应类是Field、Method、Contructor、Package等。获得这些类的实例对象后就获得了相应类的成分。
Constructor类
Class类对应着java类的字节码,Constructor类则对应这着这些字节码中的一部分,它代表相应类类中的构造方法。
得到某个类所有的构造方法,例如得到String类的构造方法:
Constructor [] constructors=Class.forName(“java.lang.String”).getConstructors();
//先得到该类的子节码
得到某一个构造方法:
Constructor constructor=
Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
为了指明得到的是哪一个构造方法,需要将该构造方法的所有参数对应的字节码对象传递过来。
用反射的方法来实现:new String(new StringBufffer(“abc”))
Constructor constructor =String.class.getConstructor(StringBuffer.class);
//得到相应构造方法
String str=(String)constructor.newInstantce(new StringBuffer(“abc”));
//代码形式与new String(new StringBufffer(“abc”))进行比较
//得到对象,在编译时只知道调用构造方法,只有在运行时才知道调用的是哪一个
Class的newInstance方法:
用此方法可以比用Constructor更方便地使用无参数的构造方法来创建对象
例:String str=(String)Class.forName(“java.lang.String”).newInstance();
//该方法内部先得到默认的无参数的构造方法,然后用该构造方法创建对象
(在Eclipse中点右键选Source或点Alt+Shift+s,再选Generate Constructor using Fields,快速产生构造函数)
Filed类
Field代表类中的成员变量
public class ReflectPoint {
private Date birthday = new Date();
private int x;
public int y;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
import java.lang.reflect.Field;
public class ReflectTest {
public static void main(String[] args) throws Exception {
ReflectPoint pt1 = new ReflectPoint(3,5);
Field fieldY = pt1.getClass().getField("y");//参数为变量名,指示获得哪个变量
//fieldY的值是多少?是5,错!fieldY不是对象身上的变量,而是类上的,要用它去取某个对象上对应的值
System.out.println(fieldY.get(pt1));//参数为对象
Field fieldX = pt1.getClass().getDeclaredField("x");//获得私有的x
fieldX.setAccessible(true);//获得了变量x,但不一定能访问,需要设置
System.out.println(fieldX.get(pt1));
}
}
例子:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的“b”改为“a”,主要代码如下;
private static void changeStringValue(Object obj) throws Exception {
Field[] fields = obj.getClass().getFields();
for(Field field : fields){
if(field.getType() == String.class){
// getType():获得相应的类型,因为字节码是唯一的,所以此处用==进行比较
String oldValue = (String)field.get(obj);
String newValue = oldValue.replace('b', 'a');
field.set(obj, newValue);
}
}
}
Method类
Method类代表类中的成员方法
得到类中某一方法:以String类中的charAt为例,
Method methodCharAt = String.class.getMethod("charAt", int.class);
//第一个参数代表方法名,第二参数(及以后)为该方法的参数的字节码
System.out.println(methodCharAt.invoke(str1, 1));
/* invoke表示调用methodCharAt所代表的方法,methodCharAt所代表的方法是类上的,与对象无关,所以需要第一个参数指明该方法作用于的对象。第二个参数代表methodCharAt所代表的方法所用的参数。如果传递给invoke的第一参数为null,则表示该Method对象对应的是一个静态方法*/
若用1.4的jdk则上语句变为:
System.out.println(methodCharAt.invoke(str1, new Object[]{1}));
用反射的方法执行某个类中的main方法
目标:写一个程序,这个程序能够根据用户提供的类名,执行给类中的main方法。
普通方式:
class A{
public static void main(String[] args){
B.main(new String[]{"111","222","333"});
}
}
class B{
public static void main(String[] args){
}
}
但若事先不知道要启动的类的名字,要根据参数去启动某个类的main方法时:
String startingClassName = args[0];
//获得要启动的类的名字,但程序只知道它是String的一个值,不知道它代表一个类
Method mainMethod=Class.forName(startingClassName).getMethod("main", String[].class);
//mainMethod.invoke(null, new String[]{"111","222","333"});
//按照上语句运行,会有错误,因为运行时程序会把第二参数拆包,就成了三个参数而main方法只接受一个参数,所以只能用下面这两种形式
//mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});
mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
数组的反射
只要是同一种类型和相同的维度的数组,都可以反射成相同的一段字节码,即同一个Class类,java提供了数组的反射类:Array
例如:1、
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());//返回true
System.out.println(a1.getClass() == a4.getClass());//返回false
System.out.println(a1.getClass().getSuperclass().getName());
// getSuperclass()获得父类
2、
Object aObj1 = a1;
Object[] aObj4 = a3;
//因为a3是二维数组,编译程序会将每一个第二维的数组作为一个Object,这样产生的Object数组的每一个元素是一个数组。
Object[] aObj5 = a4;//编译程序会将每一个String当做Object,所以编译通过。
而:Object[] aObj3 = a1;编译就无法通过,因为基本数据类型编译程序不会将其当做Object。所以:
System.out.println(Arrays.asList(a4));//可以将数组成分打印出来:[a,b,c]
而System.out.println(Arrays.asList(a1));//不能正常打印
3、
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.println(Array.get(obj, i));
}
}else{
System.out.println(obj);
}
}
ArrayList和HashSet比较及HashCode分析
ArrayList是一个实现了Collection接口的类,Collection的各对象元素之间没有指定的顺序,允许有重复元素和多个null元素对象,即不满足排序,List各对象元素之间有顺序,允许有重复元素和多个null元素对象,ArrayList就是一个实现了List接口的类,所以在ArrayList存放的对象的引用是有位置顺序的,并且可以放多个指向同一个对象的引用。而HashSet则不能放多个指向同一个对象的引用
如果一个类产生的对象用哈希算法存储,那么该类必须覆盖Object.hashCodde方法(其返回值为散列码)和Object.equals方法。
因为即使两个值对象内容完全相同,它们从Object类所继承到的hashCodde中得到的返回值是不同的,因此我们若想让两个内容相同的值对象的hashCode方法的返回值相同,就必须覆盖从Object类所继承到的hashCodde方法。
如果根据 equals(Object) 方法的结果,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都也必须生成相同的整数结果。
如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。
当一个对象被存储进HashSet集合后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中的哈希值就不同了,在这种情况下,以该对象的当前引用作为参数去HashSet集合中去检索对象,就返回不到该对象的结果,也无法从HashSet中删除该对象,从而造成内存泄露。
反射的作用就是实现框架功能(如前面的调用类的main方法,可以处理任何类(及以后的任何类)的main方法,进行调用)
框架可以调用用户提供的类,实现其功能,而工具类则是被用户调用的,在写框架的时候无法知道要调用的类名,也就无法直接new某个实例对象,所以要用到反射。
对于用户而会有一个配置文件(扩展名为:properties)内容一般为要启动的类名,输入的格式为等式的格式:例如:className=java.util.ArrayList
小框架举例,调用ArrayList,配置文件的内容如上例,
InputStream ips = new FileInputStream("config.properties");//读取文件
Properties props = new Properties();//获取其中的属性值
/* Properties与HashMap的功能差不多,只是Properties能自动添加键值对,它能将自己的键值对在初始化时从硬盘加载到内存,也可以将键值对从内存放到硬盘*/
props.load(ips);
ips.close();
//关闭与ips相关的资源而不是关闭该对象,关闭该对象是java垃圾处理器的事
String className = props.getProperty("className");
Collection collections = (Collection)Class.forName(className).newInstance();
//产生相应的集合对象
类加载器
类可以加载.class文件进内存,自然也可以加载其他的文件,所以除了用InputStream ips = new FileInputStream("config.properties");这种方法外也可以用类加载器进行加载:,但使用类加载器这种方法只能读取,而不能写。例如
ReflectTest2.class.getClassLoader().getResourceAsStream("name");
//先调用类(此处为ReflectTest2)反过来获得加载他进来的类加载器,用getClassLoader()方法
// getResourceAsStream(name);该方法会在classpath目录下逐个查找要加载的文件
InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");
//尽管是根目录,参数中的cn前面也无斜杠
Class类中提供了在不调用getClassLoader()方法的情况下,加载文件的方法:
InputStream ips = ReflectTest2.class.getResourceAsStream("resources/config.properties");
//此处为相对目录
InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");
//此处为根目录
内省
内省用于对javabean的操作,它对应的英文单词为:IntroSpector
(javabean中应有一个无参数的构造函数)
javabean是一个特殊的java类,这个类中的方法的名称符合约定的规则,例如,有getXxx和setXxx方法,javabean的属性名称,是通过其get和set方法得知的,而不能直接通过其属性得知(javabean的属性为private的)。在javabean中,去掉get或set方法中的get或set后就可以得到其属性名,但其字母的大小写是有规定的,去掉get或set后,若第二个字母是小写的,则第一个字母也应小写;若都是大写的(不包括仅一个字母的情况,一个字母时为小写),则不变。
我们可以像对普通类一样对javabean进行编程和反射操作。而对于一般的类若它有getXxx和setXxx方法(有其中之一也可),则可以将其看成javabean,对它进行与javabean相同的有关操作,当然可以像一般类那样进行操作。
如果要在两个模块之间传递多个信息,可以将这些信息封装到一个javabean中,这种JavaBean的实例对象称为值对象(Value Object,简称VO)。
JDK中提供了对JavaBean进行操作的API,这些API就称为内省。
应用举例;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.lang.reflect.Method;
public class IntroSpectorTest {
public static void main(String[] args) throws Exception {
ReflectPoint pt1 = new ReflectPoint(3,5);
//此为被当做JavaBean的类,其有private类型的属性:x
String propertyName = "x";
Object retVal = getProperty(pt1, propertyName);
System.out.println(retVal);
Object value = 7;
setProperties(pt1, propertyName, value);
}
private static void setProperties(Object pt1, String propertyName,
Object value) throws IntrospectionException,
IllegalAccessException, InvocationTargetException {
PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pt1.getClass());
// PropertyDescriptor属于java.beans下的类,用于描述类的属性,注意参数
Method methodSetX = pd2.getWriteMethod();
//对于类的属性有读和写两种操作,get对应于读,而set对应于写。
methodSetX.invoke(pt1,value);
}
private static Object getProperty(Object 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;
}
(在Eclipse中抽取一个方法:选中要放进方法中的代码,点右键选Refactor—>Extract Method)
另一种设置和读取属性的方法较为复杂,采用遍历BeanInfo的所有属性方式来查找和设置某个类的对象的属性。调用IntroSpector.getBeanInfo方法,得到的BeanInfo对象封装了把这个类当做JavaBean看的结果信息。
将上方法体中的代码可修改为:
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;
使用Beanutils工具包设置和读取javabean的属性(均为静态方法)
使用该工具包还要添加包:commons-logging-1.1.jar
1、
ReflectPoint pt1 = new ReflectPoint(3,5);
BeanUtils.setProperty(pt1, "x", "9");
//第三个参数表示被设置的属性的值,注意类型为String
System.out.println(BeanUtils.getProperty(pt1, "x").getClass().getName());
//得到的属性值的类型也为String,而不是原类型,采用String类型便于数据的传输
若采用PropertyUtils类,则采用原属性
PropertyUtils.setProperty(pt1, "x", 9);
System.out.println(PropertyUtils.getProperty(pt1, "x").getClass().getName());
2、
Beanutils工具包支持属性链
即某一个类的某个属性的类型为类类型,并且该类类型所对应的类也可以当做javabean,那么可以通过BeanUtils,设置该属性的属性
BeanUtils.setProperty(pt1, "birthday.time", "111");
//birthday类型为Data,此处设置birthday的属性time
System.out.println(BeanUtils.getProperty(pt1, "birthday.time"));
拷贝对象的属性:copyProperties(java.lang.Object dest, java.lang.Object orig)
把javabean转换成map:describe(java.lang.Object bean)返回map
反之将map转为javabean:
void populate(java.lang.Object bean,java.util.map properties)
同样,BeanUtils可以设置map的值:
---------------------- <a href="http://edu.csdn.net/heima" target="blank">android培训</a>、<a href="http://edu.csdn.net/heima" target="blank">java培训</a>、期待与您交流! ----------------------
详细请查看:<a href="http://edu.csdn.net/heima" target="blank">http://edu.csdn.net/heima</a>
本文深入探讨了Eclipse集成开发环境(IDE)的高级使用技巧,包括显示输入帮助、查看程序中变量、修改工程名字、透视图设置、代码模板、已有工程导入、Java版本配置、新特性介绍(静态导入、可变参数、增强的for循环、基本数据类型的自动拆箱与装箱、枚举、享元模式等)、反射应用、数组反射、ArrayList与HashSet的区别、类加载器、内省对JavaBean的操作等核心内容。
&spm=1001.2101.3001.5002&articleId=6638358&d=1&t=3&u=c2164322806544a7b3dafeef989f375f)
1284

被折叠的 条评论
为什么被折叠?



