JAVA提高一:静态导入、可变参数、增强型for循环、装拆箱
国庆假期已结束,假期8天,全部在家带娃,体会到了妻子的不容易,需要好好努力来多赚钱了,言归正传。10月份开始进去JAVA 高级语法知识学习,本节复习学习的为:静态导入、可变参数、增强型for循环、装拆箱。【转摘,请注明来源:http://www.cnblogs.com/pony1223/p/7643842.html 】
一、静态导入
通常如果我们要使用静态的成员(方法和变量)必须给出提供这个静态成员的类。但是如果我们使用静态导入,使用这些静态成员的时候无需再给出他们的类名。
静态导入时JDK5.0引入的新特效,下面通过实例来说明静态导入的用法:
1.先定义一个公共类:
package study.javaenhance.util; public class Common
{
public static final int AGE = 10;
public static void output()
{
System.out.println("Hello World!");
}
}
2.在另一个包中使用时,如果不用静态导入,是这样用的:
package study.javaenhance;
import study.javaenhance.util.Common; public class StaticImport
{ public static void main(String[] args)
{
int a = Common.AGE;
System.out.println(a); Common.output();
} }
前面加入了导入语句,将Common类导入,使用其中的静态成员变量和静态方法时需要加上类名。
下面我们采用静态导入方式:
(1)语法:
import static 包名.类名.静态成员变量;
import static 包名.类名.静态成员函数;
注意导入的是成员变量和方法名。
(2)改写上面的例子
package study.javaenhance;
import static study.javaenhance.util.Common.AGE;
import static study.javaenhance.util.Common.output; public class StaticImport
{ public static void main(String[] args)
{
int a = AGE;
System.out.println(a); output();
} }
或者:
package study.javaenhance;
import static study.javaenhance.util.Common.*;
public class StaticImport
{ public static void main(String[] args)
{
int a = AGE;
System.out.println(a); output();
} }
注意点:
1.过度地使用静态导入会在一定程度上降低代码的可读性。
2.如果静态导入的多个类中存在重复的方法名称或者成员变量名称的时候,需要加上类名用于区分.
二、可变参数与重载覆写
在JDK5.0 之前,我们知道方法在接受参数的时候,其参数个数是固定的,但会存在某种场景,就该方法接受的某种类型的参数个数是不固定的,可能有1个参数,有2个参数,或者多个参数,但其内在功能是一样的,那么这个时候我们通常采用的重载的方式来来实现,代码举例如下:
package study.javaenhance; public class VarableParameter
{
public static void main(String[] args)
{
System.out.println(add(1,2));
System.out.println(add(1,2,5));
} public static int add(int x,int y)
{
return x+y;
} public static int add(int x,int y,int z)
{
return x + y +z;
} }
可以看到add 方法为求参数的和,但是传递过来的参数有2个和3个,后面也有可能传递多个过来,那就需要不断的重载,那么有没有办法优化呢?那就是可变参数的用途:减少代码量,方便输入
采用可变参数方式解决:
package study.javaenhance; public class VarableParameter
{
public static void main(String[] args)
{
System.out.println(add(1,2));
System.out.println(add(1,2,5));
} public static int add(int ... args)
{
int sum = 0;
for (int i : args)
{
sum += i;
}
return sum;
} /* public static int add(int x,int y,int z)
{
return x + y +z;
}*/ }
可变参数(Varargs)使程序员可以声明一个接受可变数目参数的方法。在调用可变参数的方法时,编译器会为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。本质上就是一个数组,对于某个声明了可变参数的方法来说,我们既可以传递离散的值,也可以传递数组对象。但如果将方法中的参数定义为数组,那么只能传递数组对象而不能传递离散的值。
注意点:
1.如果有多个参数,可变参数要定义在最后边 ... 位于变量类型和变量名之间,前后有无空格都可以;
2.一个方法不可能具有两个或两个以上的可变参数。
上面提到了重载,因此这里需要说明下重载和覆写的区别:
重载(Overloading)
(1) 方法重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型。
重载Overloading是一个类中多态性的一种表现。
(2) Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。
调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性。
(3) 重载的时候,方法名要一样,但是参数类型和个数不一样,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准。
重写(Overriding)
(1) 父类与子类之间的多态性,对父类的函数进行重新定义。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。
但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。
方法重写又称方法覆盖。
(2)若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法。
如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
(3)子类函数的访问修饰权限不能少于父类的;
重写方法的规则:
1、参数列表必须完全与被重写的方法相同,否则不能称其为重写而是重载。
2、返回的类型必须一直与被重写的方法的返回类型相同,否则不能称其为重写而是重载。
3、访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
4、重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。例如:
父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常。
而重载的规则:
1、必须具有不同的参数列表;
2、可以有不责骂的返回类型,只要参数列表不同就可以了;
3、可以有不同的访问修饰符;
4、可以抛出不同的异常;
三、增强型for循环
For-Each循环也叫增强型的for循环,或者叫foreach循环。
其语法如下:
for(type element: array)
{
System.out.println(element);
}
直接看样例:
package study.javaenhance; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; public class ForeachTest
{
public static void main(String[] args)
{
int[] arr = {1, 2, 3, 4, 5}; System.out.println("----------旧方式遍历------------"); for(int i=0;i<arr.length;i++)
{
System.out.println(arr[i]);
} System.out.println("---------新方式遍历-------------");
//新式写法,增强的for循环
for(int element:arr)
{
System.out.println(element);
} System.out.println("---------遍历二维数组-------------"); //遍历二维数组 int[][] arr2 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}} ; for(int[] row : arr2)
{
for(int element : row)
{
System.out.println(element);
}
} //以三种方式遍历集合List List<String> list = new ArrayList<String>(); list.add("a");
list.add("b");
list.add("c"); System.out.println("----------方式1-----------");
//第一种方式,普通for循环
for(int i=0;i<list.size();i++)
{
System.out.println(list.get(i));
} System.out.println("----------方式2-----------");
//第二种方式,使用迭代器
for(Iterator<String> iter = list.iterator();iter.hasNext();)
{
System.out.println(iter.next());
}
System.out.println("----------方式3-----------");
//第三种方式,使用增强型的for循环
for(String str: list)
{
System.out.println(str); } } }
四、基本数据的自动装箱和拆箱
在这之前,我们首先了解回顾下,JAVA种类型的划分为基本数据类和引用类型,其中基本数据类型为:byte short int long float double char boolean;引用类型为:数组 接口 类
那么我们本小节讲的即为基本数据类中的装箱和拆箱。
自动装箱:基本类型自动转为包装类(int >> Integer)
自动拆箱:包装类自动转为基本类型(Integer >> int)
包装类是针对于原生数据类型的包装。因为有8个原生数据类型,所以对应有8个包装类。
所有的包装类(8个)都位于java.lang下。
Java中的8个包装类分别是:Byte, Short, Integer, Long, Float, Double, Character, Boolean,它们的使用方式都是一样的,可以实现原生数据类型与包装类型的双向转换。
下面以主要Integer类为例说明。
Integer类将int类型的值包装到一个对象中。
Integer通过下面这个构造方法构造相应的整型数的对象:
public Integer(int value);
public static Integer valueOf(int i);
public int intValue()方法则返回这个包装类所包装的整型值。
举例如下:
package study.javaenhance; import java.util.ArrayList;
import java.util.Collection; public class AutoBox
{
public static void main(String[] args)
{
Integer iObj = 3; //自动将iObj 拆箱为了int 类型,然后参与运算.
System.out.println(iObj + 12); Collection<Integer> c = new ArrayList<Integer>(); c.add(3);//将int类型的3转换为Integer类型并放到集合当中 for (Integer item : c) {
System.out.println(item);
} } }
下面说一个知识点,看下面的程序:
package study.javaenhance; import java.util.ArrayList;
import java.util.Collection; public class AutoBox
{
public static void main(String[] args)
{
Integer i1 = 100;
Integer i2 = 100; System.out.println(i1 == i2); Integer i3 = Integer.valueOf(100);
Integer i4 = Integer.valueOf(100);
System.out.println(i3==i4); //
Integer i5 = 130;
Integer i6 = 130; System.out.println(i5 == i6); Integer i7 = Integer.valueOf(130);
Integer i8 = Integer.valueOf(130);
System.out.println(i7==i8); } }
上面的输出结果为:
true
true
false
false
为什么呢?
当两个数都是100的时候==判断相等,当两个数都是130的时候判断不相等。
查看内部实现代码可知,Integer类有一个缓存,它会缓存-128~127之间的整数。
当调用valueOf的时候,不会生成新的对象,而是从缓存中取出对象。这样可以提高性能。
使用构造方法的时候肯定会生成新的对象。
关于自动装箱和拆箱知识扩充:
自动装箱拆箱要点:
1.自动装箱时编译器调用valueOf将原始类型值转换成对象,同时自动拆箱时,编译器通过调用类似intValue(),doubleValue()这类的方法将对象转换成原始类型值。
2.自动装箱是将boolean值转换成Boolean对象,byte值转换成Byte对象,char转换成Character对象,float值转换成Float对象,int转换成Integer,long转换成Long,short转换成Short,自动拆箱则是相反的操作。
何时发生自动装箱和拆箱
自动装箱的弊端:
自动装箱有一个问题,那就是在一个循环中进行自动装箱操作的情况,如下面的例子就会创建多余的对象,影响程序的性能。
Integer sum = 0;
for(int i=1000; i<5000; i++){
sum+=i;
}
上面的代码sum+=i可以看成sum = sum + i,但是+这个操作符不适用于Integer对象,首先sum进行自动拆箱操作,进行数值相加操作,最后发生自动装箱操作转换成Integer对象。其内部变化如下
1.sum = sum.intValue() + i;
2.Integer sum = new Integer(result);
由于我们这里声明的sum为Integer类型,在上面的循环中会创建将近4000个无用的Integer对象,在这样庞大的循环中,会降低程序的性能并且加重了垃圾回收的工作量。因此在我们编程时,需要注意到这一点,正确地声明变量类型,避免因为自动装箱引起的性能问题。
重载与自动装箱:
当重载遇上自动装箱时,情况会比较有些复杂,可能会让人产生有些困惑。在1.5之前,value(int)和value(Integer)是完全不相同的方法,开发者不会因为传入是int还是Integer调用哪个方法困惑,但是由于自动装箱和拆箱的引入,处理重载方法时稍微有点复杂。一个典型的例子就是ArrayList的remove方法,它有remove(index)和remove(Object)两种重载,我们可能会有一点小小的困惑,其实这种困惑是可以验证并解开的,通过下面的例子我们可以看到,当出现这种情况时,不会发生自动装箱操作。
public void test(int num){
System.out.println("method with primitive argument"); } public void test(Integer num){
System.out.println("method with wrapper argument"); } //calling overloaded method
AutoboxingTest autoTest = new AutoboxingTest();
int value = 3;
autoTest.test(value); //no autoboxing
Integer iValue = value;
autoTest.test(iValue); //no autoboxing Output:
method with primitive argument
method with wrapper argument
要注意的事项:自动装箱和拆箱可以使代码变得简洁,但是其也存在一些问题和极端情况下的问题,以下几点需要我们加强注意。
1.对象相等比较
这是一个比较容易出错的地方,”==“可以用于原始值进行比较,也可以用于对象进行比较,当用于对象与对象之间比较时,比较的不是对象代表的值,而是检查两个对象是否是同一对象,这个比较过程中没有自动装箱发生。进行对象值比较不应该使用”==“,而应该使用对象对应的equals方法。看一个能说明问题的例子。
public class AutoboxingTest { public static void main(String args[]) { // Example 1: == comparison pure primitive – no autoboxing
int i1 = 1;
int i2 = 1;
System.out.println("i1==i2 : " + (i1 == i2)); // true // Example 2: equality operator mixing object and primitive
Integer num1 = 1; // autoboxing
int num2 = 1;
System.out.println("num1 == num2 : " + (num1 == num2)); // true // Example 3: special case - arises due to autoboxing in Java
Integer obj1 = 1; // autoboxing will call Integer.valueOf()
Integer obj2 = 1; // same call to Integer.valueOf() will return same
// cached Object System.out.println("obj1 == obj2 : " + (obj1 == obj2)); // true // Example 4: equality operator - pure object comparison
Integer one = new Integer(1); // no autoboxing
Integer anotherOne = new Integer(1);
System.out.println("one == anotherOne : " + (one == anotherOne)); // false } }
Output:
i1==i2 : true
num1 == num2 : true
obj1 == obj2 : true
one == anotherOne : false
值得注意的是第三个小例子,这是一种极端情况。obj1和obj2的初始化都发生了自动装箱操作。但是处于节省内存的考虑,JVM会缓存-128到127的Integer对象。因为obj1和obj2实际上是同一个对象。所以使用”==“比较返回true。
2.容易混乱的对象和原始数据值
另一个需要避免的问题就是混乱使用对象和原始数据值,一个具体的例子就是当我们在一个原始数据值与一个对象进行比较时,如果这个对象没有进行初始化或者为Null,在自动拆箱过程中obj.xxxValue,会抛出NullPointerException,如下面的代码
private static Integer count; //NullPointerException on unboxing
if( count <= 0){
System.out.println("Count is not started yet");
}
这一点需要特别注意,我之前就犯过这个错误。
3.缓存的对象
这个问题就是我们上面提到的极端情况,在Java中,会对-128到127的Integer对象进行缓存,当创建新的Integer对象时,如果符合这个这个范围,并且已有存在的相同值的对象,则返回这个对象,否则创建新的Integer对象。在Java中另一个节省内存的例子就是字符串常量池。
JAVA提高一:静态导入、可变参数、增强型for循环、装拆箱的更多相关文章
- Unity实现支持泛型的事件管理以减少使用object作为参数带来的频繁装拆箱
如果不用C#自身的event关键字而是要自己实现一个可统一管理游戏中各种消息事件通知管理的系统模块EventManger时,通常都是把事件delegate的参数定义为object类型以适应所有的数据类 ...
- Day 11:静态导入、增强for循环、可变参数的自动装箱与拆箱
jdk1.5新特性-------静态导入 静态导入的作用: 简化书写. 静态导入可以作用一个类的所有静态成员. 静态导入的格式:import static 包名.类名.静态的成员: 静态导入要注意的 ...
- static特别用法【静态导包】——Java包的静态导入
面试我问你static关键字有哪些作用,如果你答出static修饰变量.修饰方法我会认为你合格,答出静态块,我会认为你不错,答出静态内部类我会认为你很好,答出静态导包我会对你很满意,因为能看出你非常热 ...
- java基础(八) 深入解析常量池与装拆箱机制
引言 本文将介绍常量池 与 装箱拆箱机制,之所以将两者合在一起介绍,是因为网上不少文章在谈到常量池时,将包装类的缓存机制,java常量池,不加区别地混在一起讨论,更有甚者完全将这两者视为一个整体, ...
- Java枚举、静态导入、自动拆装箱、增强for循环、可变参数
一.枚举简介 1.什么是枚举? 需要在一定范围内取值,这个值只能是这个范围内中的任意一个 现实场景:交通信号灯,有三种颜色,但是每次只能亮三种颜色里面的任意一个 2.使用一个关键字 enum enum ...
- 工具类:Colletions ,Arrays(静态导入,可变参数,强循环)
一.Collecti 专门用来操作集合的工具类,没有构造函数,全静态方法. 常用方法: static <T extends Comparable<? super T>> voi ...
- java基础(20):Map、可变参数、Collections
1. Map接口 1.1 Map接口概述 我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它们存储数据的形式不同,如下图. Collection中的集合,元素是孤 ...
- JSP-讲解(生成java类、静态导入与动态导入)
一.JSP技术简介 JSP是Java Server Page的缩写,它是Servlet的扩展,它的作用是简化网站的创建和维护. JSP是HTML代码与Java代码的混合体. JSP文件通常以JSP或J ...
- Java面向对象_增强for可变参数与代码块
1.foreach循环 for(类型 变量名称:数组或集合){ //输出操作 } 2.可变参数:根据需要自动传入任意个数的参数,就是可变参数. 语法:返回值类型 方法名称(数据类型...参数名称){ ...
随机推荐
- 【DDD】领域驱动设计实践 —— 架构风格及架构实例
概述 DDD为复杂软件的设计提供了指导思想,其将易发生变化的业务核心域放置在限定上下文中,在确保核心域一致性和内聚性的基础上,DDD可以被多种语言和多种技术框架实现,具体的框架实现需要根据实际的业务场 ...
- linux环境下安装nginx步骤
开始前,请确认gcc g++开发类库是否装好,默认已经安装. ububtu平台编译环境可以使用以下指令 apt-get install build-essential apt-get install ...
- Charles 抓包
声明:本文为依依Love博主原创文章,未经博主允许不得转载 1. 简介: 2. 安装包下载: 3. 安装并替换破解版的jar包 4.设置mac代理 5. 安装证书: 6. 设置手机抓包 ...
- [自制操作系统] JOS文件系统详解&支持工作路径&MSH
本文分为两部分: 第一部分将详细分析JOS的文件系统及文件描述符的实现方法. 第二部分将实现工作路径,提供新的系统调用,完善用户空间工具. 本文中支持的新特性: 支持进程工作目录 提供getcwd与c ...
- NullpointerException处理
毫无疑问,空指针NullpointerException是我们最常遇到异常,没有之一! 在刚进入编程职业时,我想,大部分刚进入的同学肯定会受到前辈们的叮咛:一定要防止空指针,这是个低级错误.你们不是? ...
- 团队作业10--Beta阶段项目复审
小组的名字和链接 优点 缺点 最终排名 油炸咸鱼 http://www.cnblogs.com/24app/ 基本功能实现,能够完成预期达到的大部分功能,并能够修复所有自己提出的bug,界面也还行,博 ...
- 团队作业8——第二次项目冲刺(Beta阶段)Day7——5.26
展开圆桌式会议: 会议内容:1.汇总BETA阶段的成果.2.针对BETA阶段的大家的获得的收获进行了讨论.3.对整个团队项目的过程进行了总结.每个人的工作分配: 队员 今日任务 贡献比 林燕 做最后测 ...
- 【Alpha阶段】第六次scrum meeting
一.会议照片 二.会议内容 姓名 学号 负责模块 昨日任务完成度 今日任务 杨爱清 099 界面设计和交互功能 完成 设计界面 杨立鑫 100 数据库搭建和其他 完成 将数据库与其他模块连接 林 钊 ...
- 201521123074 《Java程序设计》第5周学习总结
1.本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 1.2 可选:使用常规方法总结其他上课内容. 接口定义了解:接口(interface)就是方法声明和常量值的集合. 几种接口讲解 ...
- 201521123033《Java程序设计》第5周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 参考资料: 百度脑图 XMind 2. 书面作业 作业参考文件下载 1.代码阅读:Child压缩包内源代码 1.1 com.p ...