JDK1.5新特性:
可变参数(不会发生数组越界异常)
1.可变参数会自动包装成数组,使用时当作数组使用
2.方法有多个参数时,可变参数需要放到参数列表最后(否则会报错)
3.方法的可变参数最多有一个
4.可变参数不传值时,包装了一个空数组
foreach(增强的for循环)
for(元素类型 变量名:集合类型){…}
泛型
JDK1.5以后引入三大常用新特性:泛型、枚举、注解。
泛型是一件很重要的实现技术,它可以帮助我们解决程序的参数转换问题。
泛型指的就是在类定义的时候并不会设置类中的属性或方法中的参数的具体类型,而是在类使用时再进行定义。如果要想进行这种泛型的操作,就必须做一个类型标记的声明。
泛型类
泛型类的基本语法:
class Myclass <T>{
T valuel;
}
尖括号 <> 中的 T 被称作是类型参数,用于指代任何类型。
实际上这个T你可以任意写,但出于规范的目的,Java还是建议我们用单个大写字母来代表类型参数。常见的如:
- T 代表一般的任何类。
- E 代表 Element 的意思,或者 Exception 异常的意思。
- K 代表 Key 的意思
- V 代表 Value 的意思,通常与 K 一起配合使用。
- S 代表 Subtype 的意思,文章后面部分会讲解示意。
MyClass<String> myClass1 = new MyClass<String>();
JDK1.7泛型类实例化对象时构造方法调用这里<>不需要指定类型
MyClass<String> myClass1 = new MyClass<>();
注意:泛型只能接受类,所有的基本数据类型必须使用包装类!
泛型方法
泛型方法定义:
class Myclass{
public <T> void print(T t){
System.out.println(t);
}
}
泛型方法和泛型类可以共存,二者各自独立。
泛型类与泛型方法的参数类型的字母最好区分开。
class MyClass<T>{
public void testMethod1(T t) {
System.out.println(t);
}
public <E> E testMethod2(E e) {
return e;
}
}
public class Test {
public static void main(String[] args) {
MyClass<String> myClass = new MyClass<>();
myClass.testMethod1("hello 泛型类");
Integer i = myClass.testMethod2(100);
System.out.println(i);
}
}
泛型通配符(重点)
在程序类中追加了泛型的定义后,避免了 ClassCastException 的问题,但是又会产生新的情况:参数的统一问题。
解决方案:可以接收所有的泛型类型,但是又不能够让用户随意修改。这种情况就需要使用通配符"?"来处理。?表示可以是任意类型。
public class Test {
public static void main(String[] args) {
Message<Integer> message = new Message() ;
message.setMessage(55);
fun(message);
}
// 此时使用通配符"?"描述的是它可以接收任意类型,但是由于不确定类型,所以无法修改
public static void fun(Message<?> temp){
//temp.setMessage(100); 无法修改!
System.out.println(temp.getMessage());
}
}
在"?"的基础上又产生了两个子通配符:
- ? extends 类:设置泛型上限:
例如:? extends Number,表示只能够设置Number或其子类,例如:Integer、Double等; - ? super 类:设置泛型下限:
例如:? super String,表示只能够设置String及其父类Object。
泛型上限示例:
class Message<T extends Number> { // 设置泛型上限
private T message ;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
}
public class Test {
public static void main(String[] args) {
Message<Integer> message = new Message() ;
message.setMessage(55);
fun(message);
}
// 此时使用通配符"?"描述的是它可以接收任意类型,但是由于不确定类型,所以无法修改
public static void fun(Message<? extends Number> temp){
//temp.setMessage(100); 仍然无法修改!
System.out.println(temp.getMessage());
}
}
泛型下限示例:
class Message<T> {
private T message ;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
}
public class Test {
public static void main(String[] args) {
Message<String> message = new Message() ;
message.setMessage("Hello World");
fun(message);
}
public static void fun(Message<? super String> temp){
// 此时可以修改!!
temp.setMessage("hello!");
System.out.println(temp.getMessage());
}
}
上限可以用在声明,不能修改;而下限只能用在方法参数,可以修改内容!
泛型接口
泛型接口定义与泛型类区别不大。
public interface IMessage<T>{
void print(T t);
}
泛型接口的实现类:泛型类(保留参数类型声明),不是泛型类(接口处指定具体类型)。
public interface IMessage<T>{
void print(T t);
}
class MessageImp1<T> implements IMessage<T>{
public void print(T t){
System.out.println(t);
}
}
class MessageImp2 implements IMessage<String> {
public void print(String t) {
System.out.println(t);
}
}
public class Test{
public static void main(String[] args) {
IMessage<Integer> msg = new MessageImpl() ;
IMessage<String> msg1= new MessageImp2() ;
msg.print(11);
msg1.print("Hello");
}
}
类型擦除
泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。
通俗地讲,泛型类和普通类在 java 虚拟机(JVM)内是没有什么特别的地方。
JDK1.0->JDK1.5->编译时解决该问题
泛型擦除示例:
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 Test {
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>
则类型参数就被替换成类型上限。
泛型类型擦除总结:
1.编译时的功能扩展,运行时擦除泛型信息;
2.如果泛型类型无上限类型,泛型擦除之后的类型是Object;如果泛型类型有上限类型,泛型擦除之后的类型是上限类型。