------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
正如张孝祥老师所说,每件事情都要自己去发掘,去思考,才是属于自己的,死记硬背是学不到正真的知识。这是我的第一篇学习日志,我会从学习视频中找出自己所感悟的东西,所领略的东西加以分析,希望自己能逐渐强大起来。
JDK5.0中出现的新特性
一、泛型(Generics)
二、增强的“for”循环(Enhanced For loop)
三、基本数据类型的自动拆箱与装箱(Autoboxing/Unboxing)
四、枚举(Enums)
五、可变参数(Var args)
一、泛型
1.介绍:
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
2.规则和限制:
(1)、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
(3)、泛型的类型参数可以有多个。
(4)、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上称为“有界类型”。
泛型还有接口、方法等等,内容很多,需要花费一番功夫才能理解掌握并熟练应用。
在此给出我曾经了解泛型时候写出的两个例子(根据看的印象写的),实现同样的功能,一个使用了泛型,一个没有使用,通过对比,可以很快学会泛型的应用,学会这个基本上学会了泛型70%的内容。
例子一:使用了泛型
class Gen<T> {
private T ob; //定义泛型成员变量
public Gen(T ob) {
this.ob = ob;
}
public T getOb() {
return ob;
}
public void setOb(T ob) {
this.ob = ob;
}
public void showType() {
System.out.println("T的实际类型是: " + ob.getClass().getName());
}
}
public class GenDemo {
public static void main(String[] args){
//定义泛型类Gen的一个Integer版本
Gen<Integer> intOb=new Gen<Integer>(88);
intOb.showType();
int i= intOb.getOb();
System.out.println("value= " + i);
System.out.println("----------------------------------");
//定义泛型类Gen的一个String版本
Gen<String> strOb=new Gen<String>("Hello Gen!");
strOb.showType();
String s=strOb.getOb();
System.out.println("value= " + s);
}
}
例子二:没有使用泛型
class Gen2 {
private Object ob; //定义一个通用类型成员
public Gen2(Object ob) {
this.ob = ob;
}
public Object getOb() {
return ob;
}
public void setOb(Object ob) {
this.ob = ob;
}
public void showTyep() {
System.out.println("T的实际类型是: " + ob.getClass().getName());
}
}
public class GenDemo2 {
public static void main(String[] args) {
//定义类Gen2的一个Integer版本
Gen2 intOb = new Gen2(new Integer(88));
intOb.showTyep();
int i = (Integer) intOb.getOb();
System.out.println("value= " + i);
System.out.println("---------------------------------");
//定义类Gen2的一个String版本
Gen2 strOb = new Gen2("Hello Gen!");
strOb.showTyep();
String s = (String) strOb.getOb();
System.out.println("value= " + s);
}
}
运行结果:
两个例子运行Demo结果是相同的,控制台输出结果如下:
例子一:T的实际类型是:
java
.
lang
.
Integer
value= 88
例子二:T的实际类型是: java.lang.String
value= Hello Gen!
Process finished with exit code 0
二、增强的“for”循环
1.语法:
(1)、for(type 变量名 : 集合变量名){…}
(2)、type前可以加修饰符,如final
2.注意事项:
(1)、迭代变量必须在()中定义。
(2)、集合变量可以使数据或者实现了Iterable接口的集合类。
3.引用网上的说法
(1)、增强for循环和iterator遍历的效果是一样的,也就说增强for循环的内部也就是调用iteratoer实现的(可以查看编译后的文件),但是增强for循环有些缺点,例如不能在增强循环里动态的删除集合内容。不能获取下标等。
(2)、ArrayList由于使用数组实现,因此下标明确,最好使用普通循环。(3)、而对于 LinkedList 由于获取一个元素,要从头开始向后找,因此建议使用 增强for循环,也就是iterator。
例子:
//一般的迭代遍历:
Set<String> set = new HashSet<String>();
Iterator<String> it = set.iterator();
while (it.hasNext()) {
String str = it.next();
System.out.println(str);
}
//for循环遍历:
for (String str : set) {
System.out.println(str);
}
三、基本数据类型的自动拆箱与装箱
1.什么是自动装箱拆箱?
一般我们要创建一个类的对象的时候,我们会这样:
Class a = new Class(parameter);
//当我们创建一个Integer对象时,却可以这样:
Integer i = 100; (注意:不是 int i = 100; )
实际上,执行上面那句代码的时候,系统为我们执行了:Integer i = new Integer(100); 此即基本数据类型的自动装箱功能。
2.基本数据类型与对象的差别:
基本数据类型不是对象,也就是使用int、double、boolean等定义的变量、常量。
基本数据类型没有可调用的方法。
3.什么时候自动装箱、拆箱?
1 Integer i = 10; //装箱,相当于Integer i = new Integer(100)
2 int t = i; //拆箱
//在-128~127 之外的数
Integer i1 = 200;
Integer i2 = 200;
System.out.println("i1==i2: "+(i1==i2));
// 在-128~127 之内的数
Integer i3 = 100;
Integer i4 = 100;
System.out.println("i3==i4: "+(i3==i4));
输出的结果是:
i1==i2: false
i3==i4: true
说明:
equals() 比较的是两个对象的值(内容)是否相同。
"==" 比较的是两个对象的引用(内存地址)是否相同,也用来比较两个基本数据类型的变量值是否相等。
在自动装箱时对于值从–128到127之间的值,它们被装箱为Integer对象后,会存在内存中被重用,
所以范例中,i3 与 i4实际上参考至同一个对象。
如果超过了从–128到127之间的值,被装箱后的Integer对象并不会被重用,
即相当于每次装箱时都新建一个 Integer对象,所以范例中,i1与i2参考的是不同的对象。
另外,当不使用自动装箱功能的时候,情况与普通类对象一样,请看下例:
1 Integer i3 = new Integer(100);
2 Integer i4 = new Integer(100);
3 System.out.println("i3==i4: "+(i3==i4));//显示false
四、枚举(Enums)
1.为什么要有枚举?
枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则编译器就会报错。枚举可以让编译器在编译期就可以控制源程序中的非法值。
2.枚举是什么?
枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
3.枚举的用法:
枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后面要有分号与其它成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编译器将报告错误。
(1)常量
在JDK1.5 之前,我们定义常量都是: publicstaticfianl.... 。现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。
public enum Color {
RED, GREEN, BLANK, YELLOW
}
(2)switch
JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强。
enum Signal {
GREEN, YELLOW, RED
}
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch (color) {
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}
(3)向枚举中添加新方法
如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum 实例。
public enum Color {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
// 普通方法
public static String getName(int index) {
for (Color c : Color.values()) {
if (c.getIndex() == index) {
return c.name;
}
}
return null;
}
// get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
五、可变参数(Var args)
1.介绍:
Java语言在JDK1.5中首次推出Java可变参数,variable arguments,或简称varargs。这一新语言特征给软件开发人员在编写方法重载时提供了方便和灵活性。但可变参数的应用并不像想象的那么简单,使用时有其特殊要求和局限性。
2.例子解说:
一开始接触可变参数的时候,我通过以下这几个例子理解了可变参数。
public class TestVarArgus {
public static void dealArray(int... intArray){
for (int i : intArray)
System.out.print(i +" ");
System.out.println();
}
public static void main(String args[]){
dealArray();
dealArray(1);
dealArray(1, 2, 3);
}
}
输出:
1
1 2 3
通过main方法里的调用,可以看出来这个可变参数既可以是没有参数(空参数),也可以是不定长的。看到这里估计都能明白,这个不定长的参数其实和数组参数挺像的。事实上,也确实是这么回事儿。编译器会在悄悄地把这最后一个形参转化为一个数组形参,并在编译出的class文件里作上一个记号,表明这是个实参个数可变的方法。
说到这里,我们可以来验证一下,看看是不是这个可变参数就是数组类参数?
public class TestVarArgus {
public static void dealArray(int... intArray){
for (int i : intArray)
System.out.print(i +" ");
System.out.println();
}
public static void main(String args[]){
int[] intArray = {1, 2, 3};
dealArray(intArray); //通过编译,正常运行
}
}
public class TestVarArgus {
public static void dealArray(int[] intArray){
for (int i : intArray)
System.out.print(i +" ");
System.out.println();
}
public static void main(String args[]){
dealArray(1, 2, 3); //编译错误
}
}
从上面这两段代码可以看出来,可变参数是兼容数组类参数的,但是数组类参数却无法兼容可变参数。其实对于第二段代码而言,编译器并不知道什么可变不可变,在它看来,需要定义一个dealArray(int, int, int)类的方法。所以,自然就无法去匹配数组类参数的dealArray方法了。
既然Java方法接收可变参数,那么接下来我们再来看一下下面的代码:
public class TestVarArgus {
public static void dealArray(int count, int... intArray){
}
public static void dealArray(int... intArray, int count){//编译报错,可变参数类型应该作为参数列表的最后一项
}
public static void main(String args[]){
}
}
这段代码说明了,可变参数类型必须作为参数列表的最后一项,而不能放在定长参数的前面。估计你会想到一个词“优先级”。因为没有确切的说明,只是这样一种规定,这里可以借用“优先级”这个词来理解一下,请看下面的代码:
public class TestVarArgus {
public static void dealArray(int... intArray){
System.out.println("1");
}
public static void dealArray(int count, int count2){
System.out.println("2");
}
public static void main(String args[]){
dealArray(1, 2);
}
}
代码贴出来估计都知道是输出2,而不是1。记住:能匹配定长的方法,那么优先匹配该方法。含有不定参数的那个重载方法是最后被选中的。
总结
在学习视频之后,有许多是自己并不了解的,在通过反复观看视频,再去网上看例子和网友的见解,让我对JAVA5的新特性都有很透彻的理解。希望自己能在往后的学习继续努力,努力进入黑马训练营学习更多我不曾接触过的内容。