一、JDK1.5以后的一些新特性
1.可变参数定义
public [static] [final] 返回值 方法名称([参数类型 参数名称][参数类型 ... 参数名称]){}
注:如果要传递多类参数,可变参数一定放在最后,并且只能设置一个可变参数
//计算任意参数的整数求和
public class Test1 {
public static void main(String[] args) {
//原先的方法
System.out.println(add1(new int[] {1,2}));
System.out.println(add1(new int[] {1,2,3,4,5}));
//引入可变参数之后的写法
System.out.println(add2(new int[] {1,2,9,8,5,3,2}));
System.out.println(add2(1,2,1));
//可变参数传递多类参数
System.out.println(add3("aaa",1,2,3));
System.out.println(add3("1", 2,3));
}
//之前的写法是使用数组
public static int add1(int[] data)
{
int result = 0;
for(int i=0;i<data.length;i++)
{
result+=data[i];
}
return result;
}
//JDK1.5后引入了可变参数列表的写法
public static int add2(int ... data)
{
int result = 0;
for(int i=0;i<data.length;i++)
{
result+=data[i];
}
return result;
}
//注:如果要传递多类参数,可变参数一定放在最后,并且只能设置一个可变参数
public static int add3(String s,int ... data)
{
int result = 0;
for(int i=0;i<data.length;i++)
{
result+=data[i];
}
return result;
}
}
2.foreach循环(增强版的for循环)
for(数据类型 临时变量 : 数组(集合)•) {
// 循环次数为数组长度,而每一次循环都会顺序取出数组中的一个元素赋值给临时变量
}
public class Test1 {
public static void main(String[] args) {
int[] data=new int[] {1,2,3,4};
//for循环写法来打印数组
for(int i=0;i<data.length;i++)
{
System.out.println(data[i]);
}
//JDK1.5以后引入的foreach循环
for(int i:data)
{
System.out.println(i);
}
}
}
3.静态导入
从JDK1.5开始,如果类中方法全是static方法,则可以直接把这个类的方法导入进来,这样就好比像在主类中定义的方法那样,可以被主方法直接调用。
class Mymath
{
public static int add(int x,int y)
{
return x+y;
}
public static int sub(int x,int y)
{
return x-y;
}
}
public class Test1 {
public static void main(String[] args) {
System.out.println(Mymath.add(1, 2));
System.out.println(Mymath.sub(3, 2));
System.out.println(add(6,7));
System.out.println(sub(8,3));
}
}
二、泛型
泛型指的就是在类定义的时候并不会设置类中的属性或方法中的参数的具体类型,而是在类使用时再进行定义。
如果要想进行这种泛型的操作,就必须做一个类型标记的声明。
如果要想进行这种泛型的操作,就必须做一个类型标记的声明。
1.泛型类
如果一个类被 <T> 的形式定义,那么它就被称为是泛型类。
(1)泛型类的基本语法
class MyClass<T> {
T value1;
}
其中,尖括号 <> 中的 T 被称作是类型参数,用于指代任何类型。
(2)常见的类型参数
T 代表一般的任何类
E 代表 Element 的意思,或者 Exception 异常的意思。
K 代表 Key 的意思
V 代表 Value 的意思,通常与 K 一起配合使用
S 代表 Subtype 的意思
T 代表一般的任何类
E 代表 Element 的意思,或者 Exception 异常的意思。
K 代表 Key 的意思
V 代表 Value 的意思,通常与 K 一起配合使用
S 代表 Subtype 的意思
(2)使用泛型类
注意:泛型只能接受类,所有的基本数据类型必须使用包装类
package Practise;
//泛型接收一个参数
class MyClass1<T>
{
T value1;
}
//泛型接收多个参数
class MyClass2<T,E>
{
T value1;
E value2;
}
public class Test1
{
public static void main(String[] args)
{
//泛型接收一个参数
MyClass1<String> myClass1=new MyClass1<String>();
//泛型接收多个参数
MyClass2<String,Integer> myClass2=new MyClass2<String,Integer>();
}
}
package Practise;
class Point <T>
{
private T xT;
private T yT;
public T getxT()
{
return xT;
}
public void setxT(T xT)
{
this.xT = xT;
}
public T getyT()
{
return yT;
}
public void setyT(T yT)
{
this.yT = yT;
}
}
public class Test1
{
public static void main(String[] args)
{
Point<String> point=new Point<String>();
point.setxT("x轴");
point.setyT("y轴");
//取出数据(避免向下转型)
String xString=point.getxT();
String yString=point.getyT();
System.out.println("x="+xString+",y="+yString);
}
}
2.泛型方法
(1)定义泛型方法
//定义泛型方法
class MyClass
{
public <T> void Methhod(T t)
{
System.out.println(t);
}
}
注:声明的类型参数,也可以当作返回值的类型的
//类型参数做返回值
class MyClass2
{
public <T> T Methhod(T t)
{
return t;
}
}
(2)泛型方法与泛型类
泛型方法与泛型类的不同:
泛型方法中,
<T> 中的 T 被称为
类型参数,类型参数是写在返回值前面的。
而泛型类中,
<T> 中的 T 被称为参数化类型,参数化类型是写在类名之后的
泛型方法可以与泛型类共存
class MyClass<T>//泛型类
{
public void Method1(T t) {
System.out.println(t);
}
public <T> T Method2(T t)//泛型方法
{
return t;
}
}
public class Test1 {
public static void main(String[] args) {
MyClass<String> myClass=new MyClass<>();
myClass.Method1("泛型类");
Integer integer=myClass.Method2(77);
System.out.println(integer);
}
}
其中,MyClass <T> 是泛型类,Method1 是泛型类中的普通方法,而 Method2 是一个泛型方法。而泛型类中的类型参数与泛型方法中的类型参数是没有相应的联系的,泛型方法始终以自己定义的类型参数为准。泛型类的实际类型参数是 String,而传递给泛型方法的类型参数是 Integer,两者不相干。
3.通配符
为了避免ClassCastException的问题,JDK1.5追加了泛型的定义,但是又出现了参数的统一问题。
(1)?
(2)? extends 类:泛型上限
如:? extends Number,表示只能够设置Number或其子类Integer、Double等
(3)? super 类:泛型下限
如:? super String,表示只能够设置String及其父类Object
注:上限可以用在声明,不能修改;而下限只能用在方法参数,可以修改内容
class Message<T> { private int message; public int getMessage() { return message; } public void setMessage(int i) { this.message = i; } } class Message2<T extends Number> { private T message; public T getMessage() { return message; } public void setMessage(T message) { this.message = message; } } class Message3<T> { private T message; public T getMessage() { return message; } public void setMessage(T message) { this.message = message; } } public class Test1 { public static void main(String[] args) { //通配符? public static void fun(Message<?> temp) { System.out.println(temp.getMessage()); } //设置通配符? extends 类 public static void fun2(Message2<Integer> message2) { System.out.println(message2.getMessage()); } //设置通配符? super 类 public static void fun3(Message3<String> message3){ // 此时可以修改!! //message3.setMessage("Hello java"); System.out.println(message3.getMessage()); }
}
}
4.泛型接口
定义在接口里面的泛型称为泛型接口
(1)定义泛型接口
//泛型接口
interface IMessage<T>
{
public void print1(T t);
}
(2)实现泛型接口的两种方法
第一种方法是在
子类定义时继续使用泛型
第二种方法是子类实现接口的时候明确给出具体类型
//泛型接口 interface IMessage<T> { public void print1(T t); }
//方法一 //在子类定义时继续使用泛型 class MessageImpl<T> implements IMessage<T> { public void print1(T t) { System.out.println(t); } } //方法二 //在子类实现接口时明确给出具体类型 class MessageImpl2 implements IMessage<String> { public void print1(String t) { System.out.println(t); } }
5.类型擦出
之所以泛型代码能够很好地和之前版本的代码很好地兼容,是因为泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,这就是类型擦除
package Practise;
import java.lang.reflect.Field;
class MyClass<T,E>{
private T message;
private E text;
public E getText() {
return text;
}
public void setText(E text) {
this.text = text;
}
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
public void testMethod1(T t) {
System.out.println(t);
}
}
public class Test1 {
public static void main(String[] args) {
MyClass<String,Integer> myClass1 = new MyClass<>();
Class cls = myClass1.getClass();
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getType());
}
}
}
在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,<T>则会被转译成普通的Object 类型,如果指定了上限如 <T extends String> 则类型参数就被替换成类型上限。