------- android培训、java培训、期待与您交流! ----------
静态导入:JDK1.5的新特性,它用于导入指定类的静态属性或静态方法。
语法:import static java.包名.类名.*;
演示:
package com.itheima;
import java.util.Calendar;
import static java.util.Calendar.*;
public class StaticImportDemo {
public static void main(String[] args) {
Calendar cal = getInstance();
cal.set(DATE, 25);
System.out.println(cal.getTime());
}
}
可变参数:
JDK1.5的新特性
特点:1、只能出现在参数列表最后
2、...位于变量类型和变量名之间,前后有无空格都可以
3、调用可变参数方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数
演示:
package com.itheima;
public class ChangeArgsDemo {
public static void main(String[] args) {
System.out.println(changeArgs(2,4,6,8));
}
public static int changeArgs(int ... args)
{
int sum = 0;
for(int i = 0; i < args.length; i++)
sum += args[i];
return sum;
}
}
增强for循环:
JDK1.5之后的新特性。
语法:
for(参数类型 变量名 : 数组|集合)
{
//迭代部分
}
特点:使用增强for循环遍历数组或集合时,无需指定长度,也无需根据索引来访问元素
注意:增强for循环只能遍历数组或集合,不能改变数组或集合的值
演示:
package com.itheima;
import java.util.Arrays;
public class EnhanceForDemo {
public static void main(String[] args) {
int[] arr = {12,32,24,21,37};
for(int item : arr)
{
//改变数组元素的值
item = item + 2;
System.out.print(item + " ");
}
//打印员数组
System.out.println("\n" + Arrays.toString(arr));
}
}
运行结果:14 34 26 23 39
[12, 32, 24, 21, 37]
枚举类:
JDK1.5的新特性,新增enum关键字,用以定义枚举类。
特点:1、枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,
而不是Object类。其中Enum类实现了Serializable和Comparable接口。
2、使用enum定义的非抽象枚举类默认使用final修饰,因此非抽象枚举类不能派生子类
A:为什么抽象枚举类或接口可以派生子类?而非抽象枚举类不可以
因为抽象枚举类被abstract修饰,而abstract不能和final使用
3、枚举类的构造方法只能使用private修饰,默认情况也是
4、枚举类的所有实例必须在枚举类的第一行显示列出,系统会自动添加public static final修饰
格式:每个枚举值之间以英文逗号隔开,最好以分号结束
演示:
public enum SeasonEnum {
SPRING, SUMMER, FALL, WINTER;
private SeasonEnum(){}//如果改为public,编译失败。
}
//如果把构造器和实例交换位置,编译时出错
6、所有的枚举类都提供了一个values()方法,刚方法可以遍历所有的枚举值(实例)
演示:
package com.itheima.demo;
public enum SeasonEnum {
//定义四个枚举实例
SPRING, SUMMER, FALL, WINTER;
}
package com.itheima.demo;
import com.itheima.season.Season;
public class Test {
public static void main(String[] args) {
//用数组保存所有的枚举值
SeasonEnum[] seas = SeasonEnum.values();
for(SeasonEnum item : seas)
System.out.print(item);
运行结果:SPRING SUMMER FALL WINTER
枚举类无参的实例化过程:
当在枚举类中给出一个枚举值,就创建了一个枚举类实例,
通过显示创建无参构造器来证实它的实例化过程。
演示说明:
public enum SeasonEnum {
//列出4个枚举类实例
SPRING,//public static final SeasonEnum SPRING = new SeasonEnum();
SUMMER,//public static final SeasonEnum SUMMER = new SeasonEnum();
FALL,//public static final SeasonEnum FALL = new SeasonEnum();
WINTER;//public static final SeasonEnum WINTER = new SeasonEnum();
//看构造器中的代码是否被执行
private SeasonEnum()
{
System.out.println("构造器被调用了");
}
}
/*测试类*/
public class SeasonTest {
public static void main(String[] args) {
SeasonEnum s = SeasonEnum.valueOf("SPRING");
}
}
运行结果:构造器被调用了
构造器被调用了
构造器被调用了
构造器被调用了
通过运行结果可以看出,当在主函数中调用使用枚举类时,先走了构造方法,
有几个枚举值,构造器就被调用了多少次,就创建了多少个枚举实例,
结论:枚举类的实例只能是枚举值,不能随意通过new来创建对象,无需显示调用构造器。
枚举类的带参实例化过程:
当枚举类显示的定义了带参构造方法时,列出枚举值时就必须对应传入参数
演示说明:
package com.itheima.gender;
public enum GenderEnum {
//定义两个枚举实例
//相当于public static final GenderEnum MALE = new GenderEnum("男");
MALE("男"),
//相当于public static final GenderEnum FEMALE = new GenderEnum("女");
FEMALE("女");
private GenderEnum(String sex) {
this.sex = sex;
}
//枚举类通常设置为不可变类,因此它的属性也不应该随便改变
//所以用private final修饰
private final String sex;
public String getSex()
{
return sex;
}
}
package com.itheima.gender;
/*测试类*/
public class GenderTest {
public static void main(String[] args) {
GenderEnum male = GenderEnum.MALE;
System.out.print(male.getSex() + " ");
GenderEnum female = GenderEnum.FEMALE;
System.out.print(female.getSex());
}
}
运行结果:男 女
结论:当枚举类定义了带参构造器时,如果枚举值不匹配对应的参数,编译失败
枚举值传入参数时,实际上就是调用了带参构造器创建对象,只是它无需
通过new来创建对象,也无需显示调用构造器
枚举类的特殊方法:
int compareTo(E o) 比较此枚举与指定对象的顺序。
String name() 返回此枚举常量的名称,在其枚举声明中对其进行声明。
String toString() 返回枚举常量的名称,它包含在声明中。
static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
返回带指定名称的指定枚举类型的枚举常量。
演示:
package com.itheima.demo;
public enum SeasonEnum {
SPRING, SUMMER, FALL, WINTER;
public void show(SeasonEnum s)
{
switch(s){
case SPRING:
System.out.println("春天");
break;
case SUMMER:
System.out.println("夏天");
break;
case FALL:
System.out.println("秋天");
break;
case WINTER:
System.out.println("冬天");
break;
}
}
}
package com.itheima.season;
import com.itheima.demo.SeasonEnum;
public class SeasonTest {
public static void main(String[] args) {
//通过给定的字符串常量,获取枚举类实例,
//给出的字符串常量必须是枚举实例之一,
//否则运行时引发IllegalArgumentException异常
SeasonEnum s = SeasonEnum.valueOf("SPRING");
System.out.println(s);
s.show(s);
}
}
运行结果:
SPRING
春天
int ordinal() 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。
Class<E> getDeclaringClass() 返回与此枚举常量的枚举类型相对应的 Class 对象。
枚举类中的抽象方法:
如果枚举类实现了一个接口或继承了一个抽象类,如果每个枚举实例调用该方法都具有
相同功能,那么可以直接在枚举类中重写该方法
演示:
public enum EnumClass implements A {
MALE(1),FEMALE(2);
private final int x;
private EnumClass(int x)
{
this.x = x;
}
//重写show()
public void show(){}
}
interface A
{
public abstract void show();
}
如果每个枚举类实例的实现细节不一样,那么可以通过匿名内部类的方式让每个枚举实例
都重写该方法
演示:
public enum EnumClass implements A {
MALE(1)
{
public void show() {
//实现细节
}
},
FEMALE(2)
{
public void show() {
//实现细节
}
};
private final int x;
private EnumClass(int x)
{
this.x = x;
}
}
interface A
{
public abstract void show();
}
如果该枚举类中本身就包含抽象方法,那么每个枚举实例都必须重写该方法。
注意:枚举类定义抽象方法时,不能使用abstract将类定义成抽象类,
因为系统会自动添加abstract修饰,这里不能在显示添加
模拟交通灯练习:
package com.itheima.lamp;
public enum TransLamp {
RED(40) {
@Override
public TransLamp nextLamp() {
return GREEN;
}
},
GREEN(50) {
@Override
public TransLamp nextLamp() {
return YELLOW;
}
},
YELLOW(3) {
@Override
public TransLamp nextLamp() {
return RED;
}
};
private final int time;
private TransLamp(int time)
{
this.time = time;
}
public int getTime()
{
return time;
}
public abstract TransLamp nextLamp();
}
/*测试类*/
package com.itheima.lamp;
public class Test {
public static void main(String[] args) {
TransLamp tlRed = TransLamp.RED;
System.out.println(tlRed + " 时间:" + tlRed.getTime()
+ "s,下一种灯是:" + tlRed.nextLamp());
TransLamp tlGreen = TransLamp.GREEN;
System.out.println(tlGreen + " 时间:" + tlGreen.getTime()
+ "s,下一种灯是:" + tlGreen.nextLamp());
TransLamp tlYellow = TransLamp.YELLOW;
System.out.println(tlYellow + " 时间:" + tlYellow.getTime()
+ "s,下一种灯是:" + tlYellow.nextLamp());
}
}
运行结果:
RED 时间:40s,下一种灯是:GREEN
GREEN 时间:50s,下一种灯是:YELLOW
YELLOW 时间:3s,下一种灯是:RED
Annotation(注解):
JDK1.5的新特性。它是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行
相应的处理。
Java提供的几个基本Annotation的用法,使用Annotation时要在其前面增加@符号,用于修饰它支持
的程序元素。
@Override:限定重写父类方法。它可以强制一个子类必须覆盖父类的方法。
作用:告诉编译器检查这个方法,避免了重写父类有可能出错带来的麻烦。
@Deprecated:标记元素已过时,当程序使用已过时的类或方法时,编译器将会给出警告。
@SuppressWarnings:抑制编译器警告。它会一直作用于该程序元素的所有子元素。通常情况下,
如果程序使用没有泛型限制的集合将会引起编译警告,为了避免这种警告,就可以使用它。
演示:
package com.itheima;
import java.util.ArrayList;
@SuppressWarnings(value = "unchecked")
public class ArrayListTest {
public static void main(String[] args) {
//创建一个不带泛型限制的集合
ArrayList al = new ArrayList();
al.add("hah");
}
}
通过编译上面程序,当使用@SuppressWarnings来关闭编译器警告时,一定要在括号里使用
name = "value"的形式为该Annotation的成员设置值,否则编译失败!!!
元注解:
在java.lang.annotaion包下提供了4个元注解,这4个元注解都只能用于修饰其他的Annotation定义。
@Retention:
只能用于修饰一个Annotation定义,用于指定被修饰的Annotation可以保留多长时间,
@Retention包含一个RetentionPolicy类型的value成员变量,所以使用@Retention时,
必须为该value指定值:
RetentionPolicy.CLASS:
编译器将把Annotation记录在class文件中。当运行Java程序时,JVM不再
保留Annotation。这是默认值。
RetentionPolicy.RUNTIME:
编译器将把Annotation记录在class文件中。当运行Java程序时,JVM也会
保留Annotation,程序可以通过反射获取该Annotation信息。
RetentionPolicy.SOURCE:
Annotation只保留在源代码中,编译器直接丢弃这种Annotation。
如果需要通过反射获取注解信息,就需要使用RetentionPolicy.RUNTIME
演示:
package com.itheima.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
//定义下面的MyAnnotation Annotation保留到运行时
@Retention(RetentionPolicy.RUNTIME)//== @Retention(value=RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
public abstract String show() default "hehe";
public abstract int age() default 32;
}
@Target:
@Target也只能修饰一个Annotation定义,它用于指定自定义Annotation的作用域。它也
需要指定值:
ElementType.ANNOTATION_TYPE:只能修饰Annotation
ElementType.CONSTRUCTOR:只能修饰构造器
ElementType.FIELD:只能修饰成员变量
ElementType.LOCAL_VARIABLE:只能修饰局部变量
ElementType.METHOD:只能修饰方法定义
ElementType.PACKAGE:只能修饰包定义
ElementType.PARAMETER:可以修饰参数
ElementType.TYPE:可以修饰类、接口(包括注解类型)、枚举类
演示:
package com.itheima.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.lang.model.element.Element;
@Retention(RetentionPolicy.RUNTIME)
//指定MyAnnotation只能修饰构造器
@Target(ElementType.CONSTRUCTOR)
public @interface MyAnnotation {
public abstract String show() default "hehe";
public abstract int age() default 32;
}
package com.itheima.annotation;
import java.lang.annotation.Annotation;
import javax.xml.ws.Action;
// @MyAnnotation 如果不注释,编译出错
public class AnnotationTest {
//编译通过
@MyAnnotation
public AnnotationTest(){}
@Action
@Override
public boolean equals(Object obj)
{
return true;
}
@SuppressWarnings(value = "unchecked")
// @MyAnnotation //如果不注释,编译出错
public void show()
{
}
}
自定义Annotation:
定义新的Annotation类型,使用@interface关键字定义一个新的Annotation类型。
语法举例:
public @interface MyAnnotation
{
}
定义该Annotation之后,就可以在程序的任何地方使用该Annotation。默认情况下,可用于修饰
类、接口、方法、变量等。
演示:
@MyAnnotation
public class AnnotationTest {
@MyAnnotation
public static void main(String[] args) {
@MyAnnotation
int a = 30;
}
}
自定义Annotation时,还可以带属性、方法,和定义接口的语法要求基本一样,但是其中的抽象
方法不能带参数。
演示:
public @interface MyAnnotation {
public static final String name = "haha";
public abstract String show();
//public abstract String show(int a);编译不通过
}
一旦在Annotation里定义了方法,使用该Annotation时就必须为其方法指定对应的类型参数值,
否则编译失败!!!
语法:@自定义Annotation接口(方法名1 = 对应的数据类型值, 方法名2 = 对应的数据类型值)
演示:
package com.itheima.annotation;
public @interface MyAnnotation {
public abstract String show();
public abstract int age();
}
package com.itheima.annotation;
//使用该Annotation时,给出对应类型的值,并且自定义Annotation中,
//有几个方法,就必须对应的给出几个对应的key-value对,否则编译失败
@MyAnnotation(show = "haha", age = 4)
public class AnnotationTest {
public static void main(String[] args) {
}
}
也可以在定义Annotation的方法时,通过default关键字为其制定初始值,当然初始值也必须
和所在方法对应的返回值类型相对应,否则编译失败!!!
演示:
package com.itheima.annotation;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
public abstract String show() default "hehe";
public abstract int age() default 32;
}
package com.itheima.annotation;
@MyAnnotation
public class AnnotationTest {
public static void main(String[] args) {
}
}
通过上面程序看出:如果为自定义Annotation的方法指定了默认值,在使用Annotation时,
则可以不为其指定值。当然也可以在使用Annotation时,为其指定值,则默认值就不会起作用。
根据Annotation是否可以包含成员变量,可以把Annotation分为如下两类:
1:标记Annotation:没有定义成员的Annotation类型被称为标记。这种Annotation仅利用自身
的存在与否来为我们提供信息,如@Override等
2:元数据Annotation:包含成员的Annotation,因为可以接收更多的元数据,所以也被称为
元数据Annotation。
提取Annotation信息:
Java5在java.lang.reflect包下新增了AnnotateElement接口,该接口代表程序中可以接受注释的
程序元素。该接口主要有如下几个实现类。
AccessibleObject, Class, Constructor, Field, Method, Package
当一个Annotation类型被定义为运行时Annotation后,该Annotation才会在运行时可见,JVM才会
加载对应的class文件。
AnnotatedElement接口是所有程序元素(如Class、Method、Constructor等)的父接口,所以程序
通过反射获取了某个类的AnnotatedElement对象(如Class、Method、Constructor等)之后,程序
就可以调用该对象的如下几个方法来访问Annotation信息。
1:<T extends Annotation> T getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
2:Annotation[] getAnnotations() 返回此元素上存在的所有注释。
3:Annotation[] getDeclaredAnnotations() 返回直接存在于此元素上的所有注释。
4:boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
演示:
接上面的程序
package com.itheima.annotation;
import java.lang.annotation.Annotation;
public class Test {
public static void main(String[] args) throws Exception {
if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class))
{
MyAnnotation ma = (MyAnnotation)AnnotationTest.class.
getAnnotation(MyAnnotation.class);
System.out.println(ma.age());
System.out.println(ma.show());
}
}
}
运行结果:hehe
32
泛型:
JDK1.5的新特性。用于解决安全问题,是一个类型安全机制。
好处:
1、将运行时期出现的问题(ClassCastException),转移到编译时期,方便程序员解决问题。
2、避免了强制转换带来的麻烦,增强了程序的健壮性。
格式:通过< >来定义要操作的引用数据类型,其实< >就是用来接收类型的,将要存储的数据类型传递到< >中。
演示:
import java.util.*;
public class CollectionTest
{
public static void main(String[] args)
{
//ArrayList<String> al = new ArrayList<String>();
//Java7的菱形语法,Java允许在构造器后不需要带完整的泛型信息
ArrayList<String> al = new ArrayList();
al.add("haha");
al.add("xixi");
//al.add(3);因为指定了集合只能添加String类型的元素,
//所以向集合添加其他类型的元素的时候编译出错。
Iterator<String> it = al.iterator();
while(it.hasNext())
{
String str = it.next();//因为指定了元素类型,所以不用在强转
System.out.println(str);
}
}
}
自定义泛型类、接口:
什么时候定义泛型类?
当要操作的引用数据类型不确定的时候
定义的泛型类作用于整个类中,为了让不同方法操作不同类型,而且类型还不确定,那么可以
将泛型定义在方法上。所谓泛型方法,就是在声明方法时定义一个或多个类型形参。
定义泛型方法格式:
修饰符 <T, S> 返回值类型 方法名(形参列表)
{
}
特殊之处:静态方法、静态初始化块、静态变量不可以访问类上定义的泛型,如果静态方法操作
的引用数据类型不确定,可以将泛型定义在方法上。
示例:
package com.itheima.generic;
public class GenericDemo {
public static void main(String[] args) {
Demo<String> demo = new Demo<String>();
demo.show(234); //编译通过,因为该方法定义成立泛型方法
demo.show("bbd");
Demo.printW("355");
}
}
class Demo<T>
{
//下面代码编译时出错,当创建带泛型声明的自定义类时,构造器不能增加泛型
//声明,否则编译失败。但调用该构造时,却可以传入实际参数类型。
public Demo<T>();
//如果去掉show()方法的泛型定义,编译出错,因为创建对象时,指定了类型
//而调用该方法时,传入了一个基本数据类型的参数
public <T> void show(T t)
{
System.out.println("show :" + t);
}
//通常泛型方法的参数都会使用类型变量。下面的泛型方法参数就使用类型变量W!
//在调用者调用这个方法时会给W赋值,那么参数t的类型也就确定了。
public <W> void print(W t)
{
System.out.println("print :" + t);
}
如果不加泛型,编译出错,静态方法不可以访问类上定义的泛型
public static <W> void printW(W t)
{
System.out.println("printW :" + t);
}
}
通过上面程序可以看出,泛型可以定义在类上,也可以定义在方法上。它们的不同是:方法声明
中定义的泛型形参,只能在该方法里使用,而接口、类声明的泛型形参则可以再整个类中使用。
与类、接口中使用泛型参数不同的是:方法中泛型参数无须显示传入实际类型参数
从泛型类派生子类:
定义类、接口、方法时,可以声明类型形参,当使用带泛型声明的父类、接口或方法时,父类和接口
不能再包含类型形参,应该为类型形参传入实际的参数类型。
示例:
public class A<T>{}
public class B extends A<T>{}//编译失败
调用方法时必须为所有的数据类型传入参数值,与调用方法不同的是,使用泛型类、接口时,可以
不为类型形参出入实际参数值。
示例:
public class A<T>{}
public class B extends A{}//没问题,只是有编译器警告
类型通配符:
当使用泛型时,都应该为这个泛型类传入一个类型参数,如果没有传入将引发编译器警告。如果
不知道传入的是什么类型,是否可以也用Object类定义呢?
演示说明:
package com.itheima.generic;
import java.util.ArrayList;
public class GenericTest {
public static void main(String[] args)
{
//创建一个明确泛型声明的集合
ArrayList<String> al = new ArrayList<String>();
al.add("haha");
al.add("hehe");
test(al);//编译出错
}
//下面这个方法,假设我们不知道传入的类型,用一个
//Object类型来接受
private static void test(ArrayList<Object> al)
{
}
}
上面程序编译出错,表明ArrayList<String>对象不能被当成ArrayList<Object>对象使用,也就是
说:ArrayList<String>类不是ArrayList<Object>类的子类!!!带泛型声明的Object类型不是其
它子类型的父类!!!在使用泛型类创建对象时,左右两边的类型必须一致!!!
演示:
ArrayList<String> al = new ArrayList<String>;
使用类型通配符:
类型通配符是一个"?",它的元素类型可以匹配任何类型,表示各种泛型声明类型的父类。但是,
它只能出现在引用中。
举例:ArrayList<?> al = new ArrayList<String>();
ArrayList<?> al = new ArrayList<?>();//编译失败
演示:
package com.itheima.generic;
import java.util.ArrayList;
public class GenericTest {
public static void main(String[] args)
{
ArrayList<String> al = new ArrayList<String>();
al.add("haha");
al.add("hehe");
test(al);
}
private static void test(ArrayList<?> al)
{
}
}
但这种带通配符的ArrayList仅表示它是各种泛型ArrayList的父类,并不能把元素添加到其中。
唯一的例外是null,它是所有引用类型的实例
演示:
ArrayList<?> al = new ArrayList<String>();
al.add(null);//没问题
//下面将引起编译出错
al.add("haha");
类型上限:
语法:类名或接口名<?/T extends 类名>,表示该类型只能是指定类或其子类。
举例:class Factory<T/? extends Person>
类型下限:
语法:类名或接口名<?/T super 类名>,表示该类型只能是指定类或其父类。
举例:class Factory<T/? extends Student>
------- android培训、 java培训、期待与您交流! ----------