数据类型
| 默认值 | 存储需求(字节) | 取值范围 | |
|---|---|---|---|
| byte | 0 | 1 | -2^7—2^7-1 |
| char | ‘ \u0000’ | 2 | 0—2^16-1 |
| short | 0 | 2 | -2^15—2^15-1 |
| int | 0 | 4 | -2^31—2^31-1 |
| long | 0 | 8 | -2^63—2^63-1 |
| float | 0.0f | 4 | -2^31—2^31-1 |
| double | 0.0d | 8 | -2^63—2^63-1 |
| boolean | false | 1 | true/false |
Java 不能隐式执行向下转型,因为这会使得精度降低。 但是使用 += 或者 ++ 运算符会执行隐式类型转换。
byte,short,char之间不会相互转换,他们三者在计算时首先转换为int类型。
boolean 只有两个值:true、false,可以使⽤ 1 bit 来存储,但是具体⼤⼩没有明确规定。JVM 会在编译时期将 boolean 类型的数据转换为 int,使⽤ 1 来表示 true,0 表示 false。JVM ⽀持 boolean 数组,但是是通过读写 byte 数组来实现的。
包装类型
基本类型都有对应的包装类型,基本类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。
缓存池
new Integer(123) 与 Integer.valueOf(123) 的区别在于:
new Integer(123) 每次都会新建一个对象;
Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。
基本类型对应的缓冲池如下:
| 包装类 | 范围 |
|---|---|
| Boolean | true和false |
| Byte | -128~127 |
| Short | -128~127 |
| Integer | -128~127 |
| Long | -128~127 |
| Byte | \u0000~\u007F |
| Float | 无 |
| Double | 无 |
在 jdk 1.8 所有的数值类缓冲池中, Integer 的缓冲池 IntegerCache 很特殊,这个缓冲池的下界是 -128,上界默认是 127,但是这个上界是可调的,在启动 jvm 的时候,通过 -XX:AutoBoxCacheMax=
String
String 被声明为 final,因此它不可被继承。 (Integer 等包装类也不能被继承)
在 Java 8 中, String 内部使用 char 数组存储数据。
在 Java 9 之后,String 类的实现改用 byte 数组存储字符串,同时使用 coder 来标识使⽤了哪种编码。
不可变的好处
可以缓存 hash 值
因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash值也不可变,因此只需要进行一次计算。
2. String Pool 的需要
如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
3. 安全性
String 经常作为参数, String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果String 是可变的,那么在网络连接过程中, String 被改变,改变 String 的那一方以为现在连接的是其它主机,而实际情况却不一定是。
4. 线程安全
String 不可变性天生具备线程安全,可以在多个线程中安全地使用。String, StringBuffer and StringBuilder
可变性
String 不可变
StringBuffer 和 StringBuilder 可变
2. 线程安全
String 不可变,因此是线程安全的
StringBuilder 不是线程安全的
StringBuffer 是线程安全的,内部使用synchronized 进行同步intern()
字符串常量池(String Pool)保存着所有字符串字面量(literal strings),这些字面量在编译时期就确定。不仅如此,还可以使用 String 的 intern() 方法在运行过程将字符串添加到 String Pool 中。
当⼀个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。
下面示例中, s1 和 s2 采用 new String() 的方式新建了两个不同字符串,而 s3 和 s4 是通过 s1.intern()和 s2.intern() 方法取得同一个字符串引用。 intern() 首先把 “aaa” 放到 String Pool 中,然后返回这个字符串引用,因此 s3 和 s4 引用的是同一个字符串。
在 Java 7 之前, String Pool 被放在运行时常量池中,它属于永久代。而在 Java 7, String Pool 被移到堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。
intern() jdk6和jdk7及以上的区别:
jdk1.6中,将这个字符串对象尝试放入串池。
- ➢如果字符串常量池中有,则并不会放入。返回已有的串池中的对象的地址
- ➢如果没有,会把此对象复制一份,放入串池,并返回串池中的对象地址
Jdk1.7起,将这个字符串对象尝试放入串池。
switch表达式后面的数据类型只能是byte,short,char,int四种整型类型,枚举类型和java.lang.String类型(从java 7才允许),不能是boolean,long,float,double类型。
关键字
final
对于基本类型, final 使数值不变;
对于引用类型, final 使引用不变,也就不能引用其它对象,但是被引用的对象本身是可以修改的。
final声明的方法不能被子类重写。
private 方法隐式地被指定为 final,如果在子类中定义的方法和基类中的一个 private 方法签名相同,此时子类的方法不是重写基类方法,而是在子类中定义了一个新的方法。
final声明的类不允许被继承。
static
静态变量
静态变量:又称为类变量,也就是说这个变量属于类的,类所有的实例都共享静态变量,可以直接通过类名来访问它。静态变量在内存中只存在一份。
实例变量:每创建一个实例就会产生一个实例变量,它与该实例同生共死。
2. 静态方法
静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。
只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字,因此这两个关键字与具体对象关联。
3. 静态语句块
静态语句块在类初始化时运行一次。
4. 静态内部类
非静态内部类依赖于外部类的实例,也就是说需要先创建外部类实例,才能用这个实例去创建非静态内部类。而静态内部类不需要。
静态内部类不能访问外部类的非静态的变量和方法。
初始化顺序
静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序。最后才是构造函数的初始化。
存在继承的情况下,初始化顺序为:
父类(静态变量、静态语句块)
子类(静态变量、静态语句块)
父类(实例变量、普通语句块)
父类(构造函数)
子类(实例变量、普通语句块)
子类(构造函数)Object 通用方法
equals()
等价关系
两个对象具有等价关系,需要满足以下五个条件:
自反性 :x.equals(x); // true
对称性:x.equals(y) == y.equals(x); // true
传递性:if (x.equals(y) && y.equals(z)) x.equals(z); // true;
一致性:多次调用 equals() 方法结果不变
与 null 的比较:对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false
2. 等价与相等
对于基本类型, == 判断两个值是否相等,基本类型没有 equals() 方法。
对于引用类型, == 判断两个变量是否引用同一个对象,而 equals() 判断引用的对象是否等价。
3. 实现
检查是否为同一个对象的引用,如果是直接返回 true;
检查是否是同一个类型,如果不是,直接返回 false;
将 Object 对象进行转型;
判断每个关键域是否相等。
hashCode()
hashCode() 返回哈希值,而 equals() 是用来判断两个对象是否等价。等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价,这是因为计算哈希值具有随机性,两个值不同的对象可能计算出相同的哈希值。
在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象哈希值也相等。
HashSet 和 HashMap 等集合类使用了 hashCode() 方法来计算对象应该存储的位置,因此要将对象添加到这些集合类中,需要让对应的类实现 hashCode() 方法。
toString()
默认返回 ToStringExample@4554617c 这种形式,其中 @ 后面的数值为散列码的无符号十六进制表示。
clone()
- cloneable
clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。重写clone()方法要实现Cloneable 接口,如果一个类没有实现 Cloneable 接口又调用了clone() 方法,就会抛出CloneNotSupportedException。
2.浅拷贝
拷贝对象和原始对象的引用类型引用同一个对象。
3. 深拷贝
拷贝对象和原始对象的引用类型引用不同对象。
4. clone() 的替代方案
使用 clone() 方法来拷贝一个对象即复杂又有风险,它会抛出异常,并且还需要类型转换。最好不要去使用 clone(),可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。
继承
访问权限
Java 中有四个访问权限修饰符: private、default 、protected 以及 public,如果不加访问修饰符,默认是default,表示包级可见。
可以对类或类中的成员(字段和方法)加上访问修饰符。
类可见表示其它类可以用这个类创建实例对象。
成员可见表示其它类可以用这个类的实例对象访问到该成员;
protected 用于修饰成员,表示在继承体系中成员对于子类可见,但是这个访问修饰符对于类没有意义。
如果子类的方法重写了父类的方法,那么子类中该方法的访问级别不允许低于父类的访问级别。这是为了确保可以使用父类实例的地方都可以使用子类实例去代替,也就是确保满足里氏替换原则。
字段决不能是公有的,因为这么做的话就失去了对这个字段修改行为的控制,客户端可以对其随意修改。抽象类与接口
抽象类
抽象类和抽象方法都使用 abstract 关键字进行声明。如果一个类中包含抽象方法,那么这个类必须声明为抽象类。
抽象类和普通类最大的区别是,抽象类不能被实例化,只能被继承。
接口
接口是抽象类的延伸,在 Java 8 之前,它可以看成是一个完全抽象的类,也就是说它不能有任何的方法实现。
从 Java 8 开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在 Java 8 之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类,让它们都实现新增的方法。
接口的成员(字段 + 方法)默认都是 public 的,并且不允许定义为 private 或者 protected。从 Java 9开始,允许将方法定义为 private,这样就能定义某些复用的代码又不会把方法暴露出去。
接口的字段默认都是 static 和 final 的 。
比较
从设计层面上看,抽象类提供了一种 IS-A 关系,需要满足里式替换原则,即子类对象必须能够替换掉所有父类对象。而接口更像是一种 LIKE-A 关系,它只是提供一种方法实现契约,并不要求接口和实现接口的类具有 IS-A 关系。
从使用上来看,一个类可以实现多个接口,但是不能继承多个抽象类。
接口的字段只能是 static 和 final 类型的,而抽象类的字段没有这种限制。
接口的成员只能是 public 的,而抽象类的成员可以有多种访问权限。
重写与重载
重写(Override)
存在于继承体系中,指子类实现了一个与父类在方法声明上完全相同的一个方法。
为了满足里式替换原则,重写有以下三个限制:
子类方法的访问权限必须大于等于父类方法;
子类方法的返回类型必须是父类方法返回类型或为其子类型。
子类方法抛出的异常类型必须是父类抛出异常类型或为其子类型。
使用 @Override 注解,可以让编译器帮忙检查是否满足上面的三个限制条件。
重载(Overload)
存在于同一个类中,指一个方法与已经存在的方法名称上相同,但是参数类型、个数、顺序至少有一个
不同。应该注意的是,返回值不同,其它都相同不算是重载。
反射
每个类都有一个 Class 对象,包含了与类有关的信息。当编译一个新类时,会产⽣生一个同名的 .class文件,该文件内容保存着 Class 对象。
类加载相当于 Class 对象的加载,类在第一次使用时才动态加载到 JVM 中。也可以使用Class.forName(“com.mysql.jdbc.Driver”) 这种方式来控制类的加载,该方法会返回一个 Class 对象。
反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时期该类的 .class 不存在也可以加载进来。
Class 和 java.lang.reflect 一起对反射提供了支持, java.lang.reflect 类库主要包含了以下三个类:
Field :可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
Method :可以使用 invoke() 方法调用与 Method 对象关联的方法;
Constructor :可以用 Constructor 的 newInstance() 创建新的对象。
反射的优点:
可扩展性 :应用程序可以利用全限定名创建可扩展对象的实例,来使用来自外部的用户自定义类。
类浏览器和可视化开发环境 :一个类浏览器需要可以枚举类的成员。可视化开发环境(如 IDE)可以从利用反射中可用的类型信息中受益,以帮助程序员编写正确的代码。
调试器和测试工具 : 调试器需要能够检查一个类里的私有成员。测试工具可以利用反射来自动地调用类里定义的可被发现的 API 定义,以确保一组测试中有较高的代码覆盖率。
反射的缺点:
尽管反射非常强大,但也不能滥用。如果一个功能可以不用反射完成,那么最好就不用。在我们使用反射技术时,下面几条内容应该牢记于心。
性能开销 :反射涉及了动态类型的解析,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。
安全限制 :使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如 Applet,那么这就是个问题了。
内部暴露 :由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用,这可能导致代码功能失调并破坏可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
反射的基本运用
获得 Class 对象
(1) 使用 Class 类的 forName 静态方法:
比如在 JDBC 开发中常用此方法加载数据库驱动:Class.forName(driver);
(2)直接获取某一个对象的 class:
Class<?> klass = int.class;Class<?> classInt = Integer.TYPE;
(3)调用某个对象的 getClass() 方法:
StringBuilder str = new StringBuilder("123");Class<?> klass = str.getClass();
创建实例
使用Class对象的
newInstance()方法来创建Class对象对应类的实例。调用默认构造器。Class<?> c = String.class;Object str = c.newInstance();
先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。
//获取String所对应的Class对象Class<?> c = String.class;//获取String类带一个String参数的构造器Constructor constructor = c.getConstructor(String.class);//根据构造器创建实例Object obj = constructor.newInstance("23333");System.out.println(obj);
获取方法
获取某个Class对象的方法集合,主要有以下几个方法:
getDeclaredMethods方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。public Method[] getDeclaredMethods() throws SecurityException
getMethods方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。public Method[] getMethods() throws SecurityException
getMethod方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。public Method getMethod(String name, Class<?>... parameterTypes)
获取类的成员变量(字段)信息
主要是这几个方法,在此不再赘述:
getFiled:访问公有的成员变量getDeclaredField:所有已声明的成员变量,但不能得到其父类的成员变量
getFileds 和 getDeclaredFields 方法用法同上(参照 Method)。
关于setAccessible方法的使用
Method和Field、 Constructor对象都有setAccessible()方法。
setAccessible启动和禁用访问安全检查的开关。
参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
提高反射的效率。 如果代码中必须用反射, 而该句代码需要频繁的被调用, 那么请设置为true。
使得原本无法访问的私有成员也可以访问
参数值为false则指示反射的对象应该实施Java语言访问检查。
调用方法
当我们从类中获取了一个方法后,我们就可以用 invoke() 方法来调用这个方法。
利用反射创建数组
数组在Java里是比较特殊的一种类型,它可以赋值给一个Object Reference。下面我们看一看利用反射创建数组的例子:
public static void testArray() throws ClassNotFoundException {Class<?> cls = Class.forName("java.lang.String");Object array = Array.newInstance(cls,25);//往数组里添加内容Array.set(array,0,"hello");Array.set(array,1,"Java");Array.set(array,2,"fuck");Array.set(array,3,"Scala");Array.set(array,4,"Clojure");//获取某一项的内容System.out.println(Array.get(array,3));}
其中的Array类为java.lang.reflect.Array类。我们通过Array.newInstance()创建数组对象。
异常
Throwable 可以用来表示任何可以作为异常抛出的类,分为两种:Error 和 Exception。其中 Error用来表示 JVM 无法处理的错误, Exception 分为两种:
受检异常 :需要用 try…catch… 语句捕获并进行处理,并且可以从异常中恢复;
非受检异常 :是程序运行时错误,例如除 0 会引发 Arithmetic Exception,此时程序崩溃并且无法恢复。
Java异常处理的方式:
方式一: try-catch-finally
方式二: throws + 异常类型
自定义异常类
一般地,用户自定义异常类都是RuntimeException的子类。
自定义异常类通常需要编写几个重载的构造器。
自定义异常需要提供serialVersionUID
自定义的异常通过throw抛出。
自定义异常最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型。
泛型
什么是泛型?为什么要使用泛型?
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮。
自定义泛型
1.泛型接口、泛型类interface List<T> 和 class GenTest<K,V>
其中, T,K,V不代表值,而是表示类型。 这里使用任意字母都可以。常用T表示,是Type的缩写。
//泛型类public class Generic<T>{}//泛型接口public interface Generator<T> {}
注意点:
1. 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:
2. 泛型类的构造器: public GenericClass(){}。错误示例: public GenericClass
3. 实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。
4. 泛型不同的引用不能相互赋值。
5. 泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价于Object。经验:泛型要使用一路都用。要不用,一路都不要用。
6. 如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。
7. jdk1.7,泛型的简化操作: ArrayList
8. 泛型的指定中不能使用基本数据类型,可以使用包装类替换。
9. 在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法中不能使用类的泛型。
10. 异常类不能是泛型的
2.泛型方法
方法,也可以被泛型化,不管此时定义在其中的类是不是泛型类。 在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。
泛型方法的格式:
[访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常
public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,IllegalAccessException{T instance = tClass.newInstance();return instance;}
通配符
类型通配符一般是使用?代替具体的类型实参,注意了,此处’?’是类型实参,而不是类型形参 。重要说三遍!此处’?’是类型实参,而不是类型形参 ! 此处’?’是类型实参,而不是类型形参 !再直白点的意思就是,此处的?和Number、String、Integer一样都是一种实际的类型,可以把?看成所有类型的父类。是一种真实的类型。
可以解决当具体类型不确定的时候,这个通配符就是 ? ;当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能。那么可以用 ? 通配符来表未知类型。
通配符指定上限
上限extends:使用时指定的类型必须是继承某个类,或者实现某个接口,即<=
通配符指定下限
下限super:使用时指定的类型不能小于操作的类,即>=
枚举
使用 enum 定义的枚举类默认继承了 java.lang.Enum类,因此不能再继承其他类
枚举类的构造器只能使用 private 权限修饰符
枚举类的所有实例必须在枚举类中显式列出(, 分隔 ; 结尾)。列出的实例系统会自动添加 public static final 修饰
必须在枚举类的第一行声明枚举类对象
枚举类的属性
枚举类对象的属性不应允许被改动, 所以应该使用 private final 修饰
枚举类的使用 private final 修饰的属性应该在构造器中为其赋值
若枚举类显式的定义了带参数的构造器, 则在列出枚举值时也必须对应的传入参数
注解(Annotation)
Annotation 其实就是代码里的特殊标记, 这些标记可以在编译, 类加载, 运行时被读取, 并执行相应的处理。通过使用 Annotation, 程序员
可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息。 代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证
或者进行部署。
Annotation 可以像修饰符一样被使用, 可用于修饰包,类, 构造器, 方法, 成员变量, 参数, 局部变量的声明, 这些信息被保存在 Annotation
的 “name=value” 对中。
生成文档相关的注解
@author 标明开发该类模块的作者, 多个作者之间使用,分割
@version 标明该类模块的版本
@see 参考转向, 也就是相关主题
@since 从哪个版本开始增加的
@param 对方法中某参数的说明, 如果没有参数就不能写
@return 对方法返回值的说明, 如果方法的返回值类型是void就不能写
@exception 对方法可能抛出的异常进行说明 , 如果方法没有用throws显式抛出的异常就不能写
其中
@param @return 和 @exception 这三个标记都是只用于方法的。
@param的格式要求: @param 形参名 形参类型 形参说明
@return 的格式要求: @return 返回值类型 返回值说明
@exception的格式要求: @exception 异常类型 异常说明
@param和@exception可以并列多个
编译时进行格式检查注解
@Override: 限定重写父类方法, 该注解只能用于方法
@Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择
@SuppressWarnings: 抑制编译器警告
自定义 Annotation
定义新的 Annotation 类型使用 @interface 关键字
自定义注解自动继承了java.lang.annotation.Annotation接口
Annotation 的成员变量在 Annotation 定义中以无参数方法的形式来声明。 其方法名和返回值定义了该成员的名字和类型。 我们称为配置参数。 类型只能是八种基本数据类型、 String类型、 Class类型、 enum类型、 Annotation类型、以上所有类型的数组。
可以在定义 Annotation 的成员变量时为其指定初始值, 指定成员变量的初始值可使用 default 关键字
如果只有一个参数成员, 建议使用参数名为value
如果定义的注解含有配置参数, 那么使用时必须指定参数值, 除非它有默认值。 格式是“参数名 = 参数值” , 如果只有一个参数成员, 且名称为value,可以省略“value=”
没有成员定义的 Annotation 称为标记; 包含成员变量的 Annotation 称为元数据 Annotation
注意: 自定义注解必须配上注解的信息处理流程才有意义。
元注解
JDK 的元 Annotation 用于修饰其他 Annotation 定义,JDK5.0提供了4个标准的meta-annotation类型, 分别是:
Retention
Target
Documented
Inherited
@Retention: 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 的生命周期, @Rentention 包含一个 RetentionPolicy 类型的成员变量, 使用@Rentention 时必须为该 value 成员变量指定值:
RetentionPolicy.SOURCE:在源文件中有效(即源文件保留) , 编译器直接丢弃这种策略的注释
RetentionPolicy.CLASS:在class文件中有效(即class保留) , 当运行 Java 程序时, JVM不会保留注解。 这是默认值
RetentionPolicy.RUNTIME:在运行时有效(即运行时保留) , 当运行 Java 程序时, JVM 会保留注释。程序可以通过反射获取该注释。
@Target: 用于修饰 Annotation 定义, 用于指定被修饰的 Annotation 能用于修饰哪些程序元素。 @Target 也包含一个名为 value 的成员变量。
@Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被javadoc 工具提取成文档。 默认情况下, javadoc是不包括注解的。
定义为Documented的注解必须设置Retention值为RUNTIME。
@Inherited: 被它修饰的 Annotation 将具有继承性。如果某个类使用了被@Inherited 修饰的 Annotation, 则其子类将自动具有该注解。比如:如果把标有@Inherited注解的自定义的注解标注在类级别上,子类则可以继承父类类级别的注解。实际应用中,使用较少
Java8注解新特性
在Java 8之前, 注解只能是在声明的地方所使用, Java8开始, 注解可以应用在任何地方。
ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中(如: 泛型声明) 。
ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中。
日期时间API
JDK8之前
- java.lang.System类
System类提供的currentTimeMillis()用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。
此方法适于计算时间差。
2. java.util.Date类
表示特定的瞬间,精确到毫秒
构造器:
Date(): 使用无参构造器创建的对象可以获取本地当前时间。
Date(long date)
常用方法
getTime():返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
toString():把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天 (Sun, Mon, Tue,
Wed, Thu, Fri, Sat), zzz是时间标准。
其它很多方法都过时了。
3. java.text.SimpleDateFormat类
Date类的API不易于国际化,大部分被废弃了, java.text.SimpleDateFormat类是一个不与语言环境有关的方式来格式化和解析日期的具体类。
格式化:SimpleDateFormat():默认的模式和语言环境创建对象SimpleDateFormat(String pattern): 该构造方法可以用参数pattern指定的格式创建一个对象,该对象调用:format(Date date): 方法格式化时间对象date
解析:public Date parse(String source): 从给定字符串的开始解析文本,以生成一个日期。
4. java.util.Calendar(日历)类
Calendar是一个抽象基类,主用用于完成日期字段之间相互操作的功能。
获取Calendar实例的方法
使用Calendar.getInstance()方法
调用它的子类GregorianCalendar的构造器。
一个Calendar的实例是系统时间的抽象表示,通过get(int field)方法来取得想要的时间信息。比如YEAR、 MONTH、 DAY_OF_WEEK、 HOUR_OF_DAY 、MINUTE、 SECOND
public void set(int field,int value)
public void add(int field,int amount)
public final Date getTime()
public final void setTime(Date date)
注意:
获取月份时: 一月是0,二月是1,以此类推, 12月是11
获取星期时: 周日是1,周二是2 , 。 。。。周六是7新日期时间API
Java 8 吸收了 Joda-Time 的精华,以一个新的开始为 Java 创建优秀的 API。新的 java.time 中包含了所有关于本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类。历史悠久的 Date 类新增了 toInstant() 方法,用于把 Date 转换成新的表示形式。这些新增的本地化时间日期 API 大大简化了日期时间和本地化的管理。
LocalDate、 LocalTime、 LocalDateTime 类是其中较重要的几个类,它们的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。
LocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期。
LocalTime表示一个时间,而不是日期。
LocalDateTime是用来表示日期和时间的, 这是一个最常用的类之一。
瞬时: Instant
Instant:时间线上的一个瞬时点。 这可能被用来记录应用程序中的事件时间戳。
在处理时间和日期的时候,我们通常会想到年,月,日,时,分,秒。然而,这只是时间的一个模型,是面向人类的。第二种通用模型是面向机器的,或者说是连续的。在此模型中,时间线中的一个点表示为一个很大的数,这有利于计算机处理。 在UNIX中,这个数从1970年开始,以秒为的单位;同样的,在Java中,也是从1970年开始,但以毫秒为单位。
java.time包通过值类型Instant提供机器视图,不提供处理人类意义上的时间单位。 Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。概念上讲, 它只是简单的表示自1970年1月1日0时0分0秒( UTC)开始的秒数。 因为java.time包是基于纳秒计算的,所以Instant的精度可以达到纳秒级。
格式化与解析日期或时间
java.time.format.DateTimeFormatter 类:该类提供了三种格式化方法:
预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
本地化相关的格式。如: ofLocalizedDateTime(FormatStyle.LONG)
自定义的格式。如: ofPattern(“yyyy-MM-dd hh:mm:ss”)
Java比较器
Java实现对象排序的方式有两种:
自然排序: java.lang.Comparable
定制排序: java.util.Comparator
Comparable
1.Comparable接口对实现它的每个类的对象强加一个整体排序。 这个排序被称为类的自然排序 ,类的compareTo方法被称为其自然比较方法。该接口有且只有一个方法int compareTo(T o)所以继承此接口需要实现该方法。compareTo返回值-1、0、1。
2.Collections.sort (和Arrays.sort )可以自动对实现此接口的对象进行列表(和数组)排序。 实现该接口的对象,可以使用如在键sorted map或作为在元件sorted set ,而不需要指定一个comparator 。
Comparator
1.比较功能,对一些对象的集合施加了一个整体排序 。可以将比较器传递给排序方法(如Collections.sort或Arrays.sort ),以便对排序顺序进行精确控制。比较器还可以用来控制某些数据结构(如顺序sorted sets或sorted maps ),或对于不具有对象的集合提供的排序natural ordering 。
2.通过比较c上的一组元素S的确定的顺序对被认为是与equals一致当且仅当c.compare(e1, e2)==0具有用于S每e1和e2相同布尔值e1.equals(e2)。
3.一般是在比较器例如: Collections.sort(List
System类
System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。
该类位于java.lang包。
由于该类的构造器是private的,所以无法创建该类的对象,也就是无法实例化该类。其内部的成员变量和成员方法都是static的, 所以也可以很方便的进行调用。
成员变量
System类内部包含in、 out和err三个成员变量,分别代表标准输入流(键盘输入),标准输出流(显示器)和标准错误输出流(显示器)。
成员方法
native long currentTimeMillis():
该方法的作用是返回当前的计算机时间,时间的表达格式为当前计算机时间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数。
void exit(int status):
该方法的作用是退出程序。其中status的值为0代表正常退出,非零代表异常退出。 使用该方法可以在图形界面编程中实现程序的退出功能等。
void gc():
该方法的作用是请求系统进行垃圾回收。至于系统是否立刻回收,则取决于系统中垃圾回收算法的实现以及系统执行时的情况。
String getProperty(String key):
该方法的作用是获得系统中属性名为key的属性对应的值。系统中常见的属性名以及属性的作用如下表所示:
BigInteger与BigDecimal
Integer类作为int的包装类,能存储的最大整型值为231-1, Long类也是有限的,最大为263-1。 如果要表示再大的整数,不管是基本数据类型还是他们的包装类都无能为力,更不用说进行运算了。
java.math包的BigInteger可以表示不可变的任意精度的整数。 BigInteger 提供所有 Java 的基本整数操作符的对应物,并提供 java.lang.Math 的所有相关方法。
另外, BigInteger 还提供以下运算:模算术、 GCD 计算、质数测试、素数生成、位操作以及一些其他操作。
构造器:BigInteger(String val): 根据字符串构建BigInteger对象
一般的Float类和Double类可以用来做科学计算或工程计算,但在商业计算中,要求数字精度比较高,故用到java.math.BigDecimal类。
BigDecimal类支持不可变的、任意精度的有符号十进制定点数。
构造器
public BigDecimal(double val)
public BigDecimal(String val)
