配色: 字号:
JAVA进阶之旅
2016-10-08 | 阅:  转:  |  分享 
  
JAVA进阶之旅

JAVA进阶之旅(一)

for循环在我们的开发中是非常非常的多的,但是有多少人会用增强for循环?其实还是有很多人会用哈,但是还是有很多人一知半解,我们来看一下增强for循环的格式是怎样的

语法

for(type变量名:集合变量名){….}

注意事项

1.迭代变量必须在括号内定义

2.集合变量可以是数组或实现了iterable接口的集合类

我们写一个小例子来查看一下就知道了

publicclassForClass{



publicstaticvoidmain(String[]args){



int[]mInt={1,3,5,7,9};



for(intx:mInt){

System.out.println("result:"+x);

}

}

}



输出的结果也是总所周知,全部输出来了,这里就不演示了,这就是比较简单的增强for循环了

二.基本数据类型的自动拆箱与装箱



这个基本数据类型的拆箱与装箱是什么呢?这样,我们用思路来说明,我们看这段代码

Integernum1=3;



如果详细分析的话,应该是把一个基本数据类型3装箱成了Integer赋值给了num1,如果你使用过以前的JDK版本,具体是几,好像是1.5还是1.6之前是会报错的,再来看下拆箱,其实可以看一下这段代码

System.out.println(num1+3);



Integer和3相加,是等于6,在现在的JDK版本早就支持了自动拆箱和装箱,所以我们现在只要了解一下就好了,这里要注意以下int范围是-128–127,如果超过了就GG

三.享元设计模式(flyweight)



同样的,这里会牵扯到一个设计模式,如果我们需要很多个对象,但是每一个对象的使用方法都是一样的,数据也是一样的,所以我们就没必要创建这么多,就创建一个就好了,可重复利用,这个就是享元设计模式了,是不是很简单

四.枚举的概述



说道枚举,他是JDK1.5新增加的一个概念,其实现在开发用的相对还是比较少的,但是你如果翻阅12年上下的代码,你可以看到很多的枚举的影子,他到底是什么呢?我们来深入了解了解



1.我们为什么要用枚举

说道这个,我们先来看个例子,比如要定义星期几或者性别的变量,我们该怎么去定义?假设用1-7分别表示星期一到星期日,但是有人可能会写成等于0去了

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



2.用普通类如何实现枚举功能

我们可以模拟一下试试看,需要做的事情有



私有的构造方法

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

可以有若干公有方法或抽象方法

我们先用基本的JAVA类来演示一下枚举的作用

publicclassWeekDay{



privateWeekDay(){

};



publicfinalstaticWeekDaySUN=newWeekDay();

publicfinalstaticWeekDayMON=newWeekDay();



publicWeekDaynextDay(){

if(this==SUN){

returnMON;

}else{

returnSUN;

}

}



publicStringtoString(){

returnthis==SUN?"SUN":"MON";

}

}



这个是我们用普通的方式来实现枚举的思想,这也是可以的,但是我们JAVA中提供了枚举的应用姿势:

五.枚举的应用



其实但从枚举来说,使用起来还是比较简单的,我们来看下是什么?

publicclassForClass{



publicstaticvoidmain(String[]args){



WeekDayweekDay=WeekDay.THI;

System.out.println(weekDay);

System.out.println(weekDay.name());

System.out.println(weekDay.ordinal());



}



publicenumWeekDay{

SUN,MON,TUE,WED,THI,FRI,SAT

}

}



这样我们就可以直接使用,并且输出的时候可以直接实现打印值的功能,就像上述我们JAVA类的功能一样

六.枚举的构造方法



我们更进一步的来演示一下其他使用方法

publicenumWeekDay{



SUN(1),MON,TUE,WED,THI,FRI,SAT;

/

1.需要在函数之后

2.必须私有

/

privateWeekDay(){

System.out.println("只要用到了这个枚举类,都会执行空构造函数");

}



privateWeekDay(intindex){

System.out.println("函数后面接参数就会调用有残构造");

}

}



这段看起来应该并不困难,主要是了解构造函数的规律和什么时候调用,注意一下就好了

七.枚举的抽象方法



我们继续来看,看下抽象函数的使用方法,我们现在假设路上的红绿灯,我们应该怎么去写?

publicenumColor{

RED(5){

@Override

publicColornextColor(){

returnGREEN;

}

},

GREEN(10){

@Override

publicColornextColor(){

returnBLUE;

}

},

BLUE(15){

@Override

publicColornextColor(){

returnRED;

}

};

//返回下一种颜色

publicabstractColornextColor();



//灯显示时间

privateinttime;



privateColor(inttime){

this.time=time;

}

}



实现起来还是有点涵养的对吧,其实思想很通顺,我们有三个灯,他都有显示下一个灯的功能,所以可以直接抽象,而且他有是都需要显示时间,所以,我们可以写一个有参的构造函数,就ok了



对了

枚举只有一个成员时,就可以作为一种单利的实现方式

JAVA进阶之旅(二)

一.认识Class类



想要反射,你就必须要了解一个类——Class,我们知道,java程序中的各个java类都属于同一事物,我们通常用Classliability描述对吧,反射这个概念从JDK1.2就出来了,历史算是比较悠久了,这个Class可不是关键字哦,这个是一个类,他代表的是一类事物;

我们归根结底就是拿到字节码对象

这里我们有三种方式是可以得到对应的实例对象(Class类型)

1.类名.class

2.对象.getClass

3.Class.forName(“类名”);—常用

我们写一个小程序来过一遍

publicclassCalssTest{



publicstaticvoidmain(String[]args)throwsClassNotFoundException{

Stringstr1="liu";

Classclass1=str1.getClass();

Classclass2=String.class;

Classclass3=Class.forName("java.lang.String");



System.out.println(class1==class2);

System.out.println(class1==class3);

System.out.println(class2==class3);



}

}



通过打印的结果我们可以知道我们都是输出同一份字节码,所以结果都是true,我们再来看,我们的Class其实还有一个方法

System.out.println(class1.isPrimitive());

System.out.println(Integer.class==int.class);

System.out.println(int.class==Integer.TYPE);



打印的结果是true,false,true,那这三又是什么意思呢?这个就留给大家猜想一下,应该很容易就知道了的

isPrimitive是否是基础类型或者原始类型

那我们的数组是什么类型呢?



宗旨,只要是在源程序中出现的类型,都有各自的Class类型,列入int[],Void等

二.反射的概念



好的。了解了Class类的神奇,我们就可以来看看反射的机制了



反射的概念:反射就是把JAVA类中的各种成分映射成相应的JAVA类,例如,一个java类中用一个Class类的对象来表示,一个类中的组成部分,成员变量,方法,构造方法,包等信息,也用一个个的JAVA类来表示,就像汽车是一个类,汽车中的发动机,变速箱也是一个类,表示JAVA的Class类要提供一系列的方法,来获取其中的变量,方法,构造方法,修饰符,包等信息,这些信息是用来相应类的实例对象表示,衙门是Field,Method,Contructor,Package等



一个类中的每一个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class来调用各种方法,我们接下来一个个讲

三.Constructor



代表的是某一个类的构造方法,我们用代码来看



publicclassCalssTest{



publicstaticvoidmain(String[]args)throwsNoSuchMethodException,InstantiationException,IllegalAccessException,IllegalArgumentException,InvocationTargetException{



//得到String的StringBuffer构造方法

Constructorconstructor=String.class.getConstructor(StringBuffer.class);

Stringstr=constructor.newInstance(newStringBuffer("str"));

System.out.println(str);

}

}



通过获得的方法用到上面相同类型的实例,再看newInstance,得到我们设置参数的构造方法,我们再来看下成员变量的反射

四.Field



这里我们就模拟了一个类,作为反射的对象



publicclassFieldClass{



publicintx;

publicinty;



publicFieldClass(intx,inty){

this.x=x;

this.y=y;

}

}



那我们实际的操作就是:

publicclassCalssTest{



publicstaticvoidmain(String[]args){



try{

//首先为x,y赋值

FieldClassfClass=newFieldClass(10,20);

//反射成员变量

Fieldfield1=fClass.getClass().getField("x");

Fieldfield2=fClass.getClass().getField("y");

//指定对象

System.out.println(field1.get(fClass));

System.out.println(field2.get(fClass));

}catch(NoSuchFieldExceptione1){

//TODOAuto-generatedcatchblock

e1.printStackTrace();

}catch(SecurityExceptione1){

//TODOAuto-generatedcatchblock

e1.printStackTrace();

}catch(IllegalArgumentExceptione){

//TODOAuto-generatedcatchblock

e.printStawww.shanxiwang.netckTrace();

}catch(IllegalAccessExceptione){

//TODOAuto-generatedcatchblock

e.printStackTrace();

}

}

}



这样我们就可以直接反射到成员变量的值了,这里我们来做一个小练习来测试一下我们成员变量的反射的理解

练习题



假设我们有一个对象中,有许多的String类型成员变量,我们的需求就是把所有对应的字符串内容”b”改成”a”

题目有了我们整理下思路,首先要做的就是定义一个对象咯



publicclassFieldClass{



publicintx;

publicinty;

publicStringstr1="boy";

publicStringstr2="bbq";

publicStringstr3="hello";



publicFieldClass(intx,inty){

this.x=x;

this.y=y;

}

@Override

publicStringtoString(){

return"FieldClass[x="+x+",y="+y+",str1="+str1+",str2="

+str2+",str3="+str3+"]";

}

}



好的,这里有三个string类型的成员变量,那我们该怎么去反射呢?



/

假设我们有一个对象中,有许多的String类型成员变量,我们

的需求就是把所有对应的字符串内容"b"改成"a"

@authorLGL



/

publicclassCalssTest{



publicstaticvoidmain(String[]args)throwsException{



FieldClassfClass=newFieldClass(5,10);

//得到所有的成員变量

Field[]fields=fClass.getClass().getFields();

for(Fieldfield:fields){

//过滤下String类型

if(field.getType()==String.class){

//取值

StringoldValue=(String)field.get(fClass);

StringnewValue=oldValue.replace("b","a");

field.set(fClass,newValue);

}

}

System.out.println(fClass);

}

}



这里思路还是比较清晰的,我们一步步的去过滤,最终更改了值



五.Method



如果前面的都是不怎么常用的,那这个我相信你绝对会喜欢,也就是方法,Method,我们来看看怎么用吧!

publicclassCalssTest{



publicstaticvoidmain(String[]args)throwsException{



Stringstr1="abc";

//反射charAt方法

Methodmethod=String.class.getMethod("charAt",int.class);

//作用对象第几个

System.out.println(method.invoke(str1,2));

}

}

这里我反射的是String的方法charAt,取第二个char,所以打印出来是c



这其实套用了一种专家模式,谁调用了这个数据,谁就是这个专家,现在我们思考一下,如果我们代码是这样写:

System.out.println(method.invoke(null,2));



这里我们不传对象,而是传一个null进去,那我们知道这个Method是调用什么吗?而纵观之下,只有static修饰的静态方法是不需要对象的,那就说明他调用的是对象了;



在JDK1.4和JDK1.5中,invoke的参数是有些区别的,不过我们现在都1.8了,自然而然这个我们不需要去考虑和追究;

六.反射Main方法



我们现在来思考一下,如何通过反射去执行一个类的Main方法,这就比较好玩了,这里就相当于一个练习题了,而题目就是:

写一个程序,这个程序能够根据用户提供的类名,去执行该类的main方法

而我们的在写这段程序之前,我们就要思考一下了,我们观察main方法:

publicstaticvoidmain(String[]args){

//main方法

}



你是否已经发现,这个main方法的参数是一个数组,,如果我们通过反射来调用这个方法,那我们该如何为invoke方法传递参数呢?



在以前的老程序员可能会在纠结JDK1.4和JDK1.5的invoke区别,但是我们倒不用去考虑这些,因为我们的版本是JDK1.8,这样吧,我们先写个需要调用的类:

publicclassMainClass{



publicstaticvoidmain(String[]args){



for(Stringarg:args){



System.out.println("Main:"+arg);

}

}

}



OK,这个类就是打印下数组的值,那我们真正的反射应该怎么去写尼?传统的调用方法是这样的:

MainClass.main(newString[]{"Hello"});



我们反射的话,就不是这么简单了,我们需要这样:

publicclassCalssTest{



publicstaticvoidmain(String[]args)throwsException{



//MainClass.main(newString[]{"Hello"});

//指定类名

//StringclassName=args[0];

//指定Main方法

Methodmain=Class.forName("MainClass").getMethod("main",

String[].class);

//调用main方法

main.invoke(null,(Object)newString[]{"Hello","LGL"});

}

}



这里为什么需要强转为Object?不是说好的传递数组吗?吗是因为JDK为了兼容老版本,如果你传递的是一个数组有多个值会进行拆包,我现在声明一个Object就是告诉他我这里只是一个对象,避免对象异常,我们看下输出的结果:



说明我们是调用成功了的;那这里就牵引出数组的反射和Object的关系了,我们继续来看;

七.数组的反射



数组实际上也是一个对象,这点我们一定要清楚,是吧

具有相同维数和元素类型的数组术语同一类型,即具有相同的Class实例对象

代表数组的Class实例对象的getSuperClass()方法返回的父类Object为对象的Class

这里我们以数组为例子就好了,我们来验证一下字节码:

int[]arr1={3};

int[]arr2={4};

//true

System.out.println(arr1.getClass()==arr2.getClass());

//[I

System.out.println(arr1.getClass().getName());



第一个为true也就验证了第一条,第二个输出的结果是[I,这个代表的是什么意思呢?[代表的是数组,I代表的是Int类型,也就是这个是int类型的数组



看一下JDK对照文档就行了



接下来,我们来看下数组的反射具体实践是什么样子的!

八.数组反射实践



我们出道题目好了在这样看起来可能更加生动形象一点

题目:怎么得到数组中的元素?

通过查看API文档,我们知道可以反射这个Array



那这个Array要怎么用呢?



假设我现在封装一个打印的方法,这个打印的方法很简单,我定义一个Object参数,你传进来什么,我就打印什么,那要是传递数组,我就一个个的打印,这样的理解应该就比较清晰了,那我们实际的操作你怎样的呢?



publicclassCalssTest{



publicstaticvoidmain(String[]args)throwsException{



int[]arr={1,3,5,7,9,2,4,6,8,10};

printObject(arr);

}



privatestaticvoidprintObject(Objectobj){

//拿到字节码

Classclasss=obj.getClass();

//判断是否是数组

if(classs.isArray()){

//得到长度

intlen=Array.getLength(obj);

//取出每一个

for(inti=0;i
System.out.print(Array.get(obj,i));

}

}else{

System.out.println(obj);

}

}

}但是如何你要问我这个数组的数据类型,我倒是没有获取到,不知为何!!!



献花(0)
+1
(本文系网络学习天...首藏)