java基础复习

抽象类和接口的对比

参数抽象类接口
默认的方法实现它可以有默认的方法实现接口完全是抽象的。它根本不存在方法的实现
实现子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现
构造器抽象类可以有构造器接口不能有构造器
与正常Java类的区别除了你不能实例化抽象类之外,它和普通Java类没有任何区别接口是完全不同的类型
访问修饰符抽象方法可以有public、protected和default这些修饰符接口方法默认修饰符是public。你不可以使用其它修饰符。
main方法抽象方法可以有main方法并且我们可以运行它接口没有main方法,因此我们不能运行它。
多继承抽象方法可以继承一个类和实现多个接口接口只可以继承一个或多个其它接口
速度它比接口速度要快接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。
添加新方法如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。如果你往接口中添加方法,那么你必须改变实现该接口的类。

equals()

  1. Obejct的equals()源码
public boolean equals(Object obj) {
        return (this == obj);
    }

从代码可知,Object类的equals方法是比较的地址,所以最初的equals方法和==的作用是一致的

像String、Double、Integer、Date、Point这些不变类都重写了equals(),重写都是为判断的根据是值,而不地址

比如String的equals()源码

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

比如Integer的equals()源码

public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

compareTo()

  public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }

   public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
   }

java中double和float精度丢失问题及解决方法

 System.out.println(0.11+2001299.32);

控制台输出2001299.4300000002

在需要精确的表示两位小数时我们需要把他们转换为BigDecimal对象,然后再进行运算。

另外需要注意

使用BigDecimal(double val)构造函数时仍会存在精度丢失问题,建议使用BigDecimal(String val)

BigDecimal

public BigDecimal(double val)

将 double 转换为 BigDecimal,后者是 double 的二进制浮点值准确的十进制表示形式。返回的 BigDecimal 的标度是使 (10scale × val) 为整数的最小值。
注:

  1. 此构造方法的结果有一定的不可预知性。有人可能认为在 Java 中写入 new BigDecimal(0.1) 所创建的 BigDecimal 正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于 0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入 到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。
  2. 另一方面,String 构造方法是完全可预知的:写入 new BigDecimal(“0.1”) 将创建一个 BigDecimal,它正好 等于预期的 0.1。因此,比较而言,通常建议优先使用 String 构造方法。
  3. 当 double 必须用作 BigDecimal 的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用 Double.toString(double) 方法,然后使用 BigDecimal(String) 构造方法,将 double 转换为 String。要获取该结果,请使用 static valueOf(double) 方法。

注解

元注解(4个)

  1. @Target – 作用域
  • ElementType.TYPE 用于描述类、接口或enum声明
  • ElementType.FIELD 用于描述实例变量
  • ElementType.METHOD 方法声明
  • ElementType.PARAMETER 参数
  • ElementType.CONSTRUCTOR 构造器
  • ElementType.LOCAL_VARIABLE 局部变量
  • ElementType.ANNOTATION_TYPE 另一个注释
  • ElementType.PACKAGE 包
  1. @Retention 生命周期,定义了该Annotation被保留的时间长短
  • RetentionPolicy.SOURCE – 在源文件中有效(即源文件保留)
  • RetentionPolicy.CLASS – 在class文件中有效(即class保留)
  • RetentionPolicy.RUNTIME– 在运行时有效(即运行时保留)
  1. @Documented 是否生成javadoc文档。

  2. @Inherited 是否被子类继承

自定义注解

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。
@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。

格式:public @interface 注解名 {定义体}

/**
 * 水果名称注解
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
    String value() default "";
}
public class Apple {
    @FruitName("Apple")
    private String appleName;
    }

Arrays.sort()原理分析

首先说一下,Collections.sort方法底层也是调用的Arrays.sort方法。

Java Arrays中提供了对所有类型的排序。其中主要分为Primitive(8种基本类型)和Object两大类。

  1. 基本类型:采用调优的快速排序;

  2. 对象类型:采用改进的归并排序。既快速(nlog(n))又稳定,对象数组中保存的只是对象的引用,这样多次移位并不会造成额外的开销,但是,对象数组对比较次数一般比较敏感,有可能对象的比较比单纯数的比较开销大很多。归并排序在这方面比快速排序做得更好,这也是选择它作为对象排序的一个重要原因之一。

排序优化:实现中快排和归并都采用递归方式,而在递归的底层,也就是待排序的数组长度小于7时,直接使用冒泡排序,而不再递归下去.

分析: 长度为6的数组冒泡排序总比较次数最多也就1+2+3+4+5+6=21次,最好情况下只有6次比较。而快排或归并涉及到递归调用等的开销,其时间效率在n较小时劣势就凸显了,因此这里采用了冒泡排序,这也是对快速排序极重要的优化。

源码中的快速排序,主要做了以下几个方面的优化

  1. 当待排序的数组中的元素个数较少时,源码中的阀值为7,采用的是插入排序。尽管插入排序的时间复杂度为0(n^2),但是当数组元素较少时,插入排序优于快速排序,因为这时快速排序的递归操作影响性能。

  2. 较好的选择了划分元(基准元素)。能够将数组分成大致两个相等的部分,避免出现最坏的情况。例如当数组有序的的情况下,选择第一个元素作为划分元,将使得算法的时间复杂度达到O(n^2).

源码中选择划分元的方法:

  • 当数组大小为 size=7 时 ,取数组中间元素作为划分元。int n=m>>1;(此方法值得借鉴)

  • 当数组大小 7<size<=40时,取首、中、末三个元素中间大小的元素作为划分元。

  • 当数组大小 size>40 时 ,从待排数组中较均匀的选择9个元素,选出一个伪中数做为划分元。

3. 普通的快速排序算法,经过一次划分后,将划分元排到素组较中间的位置,左边的元素小于划分元,右边的元素大于划分元,而没有将与划分元相等的元素放在其附近,这一点,在Arrays.sort()中得到了较大的优化,将与划分元相等的元素移到数组中间来

jdk1.7后底层实现都是TimeSort实现的。TimSort是优化后的归并排序,TimSort算法就是找到已经排好序数据的子序列,然后对剩余部分排序,然后合并起来.

foreach和while的区别(编译之后)

  1. 在while循环里,会读入一行输入,把它存入某个变量并且执行循环主体。然后,它再回头去找其他的输入行。
  2. 在foreach循环中,整行输入操作符会在列表上下文中执行(因为foreach需要逐行处理列表的内容)。在循环开始执行之前,它必须先将输入全部读进来。
  3. 当输入大容量的文件时,使用foreach会占用大量的内存。两者的差异会十分明显。因此,最好的做法,通常是尽量使用while循环的简写,让它每次处理一行。

foreach 在编译的时候编译器会自动将对for这个关键字的使用转化为对目标的迭代器的使用,这就是foreach循环的原理

创建一个类的几种方法?

  1. 使用new关键字 → 调用了构造函数
  2. 使用Class类的newInstance方法 → 调用了构造函数
Employee emp2 = (Employee)Class.forName("org.programming.mitra.exercises.Employee").newInstance();
  1. 使用Constructor类的newInstance方法 → 调用了构造函数
Constructor<Employee> constructor = Employee.class.getConstructor();
Employee emp3 = constructor.newInstance();
  1. 使用clone方法 → 没有调用构造函数
  2. 使用反序列化 → 没有调用构造函数
ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
Employee emp5 = (Employee) in.readObject();

Redirect和forward

  1. 上图所示的间接转发请求的过程如下:
    浏览器向Servlet1发出访问请求;
    Servlet1调用sendRedirect()方法,将浏览器重定向到Servlet2;
    浏览器向servlet2发出请求;
    最终由Servlet2做出响应。

  2. 上图所示的直接转发请求的过程如下:
    浏览器向Servlet1发出访问请求;
    Servlet1调用forward()方法,在服务器端将请求转发给Servlet2;
    最终由Servlet2做出响应。

Object跟这些标记符代表的java类型有啥区别呢?

Object是所有类的根类,任何类的对象都可以设置给该Object引用变量,使用的时候可能需要类型强制转换,但是用使用了泛型T、E等这些标识符后,在实际用之前类型就已经确定了,不需要再进行类型强制转换。

Java 异常的体系结构

Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。

在Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception。

Java异常层次结构图

Error:Error类对象由 Java 虚拟机生成并抛出,Error表示编译时和系统错误,通常不能预期和恢复,比如硬件故障、JVM崩溃、内存不足等 。例如,Java虚拟机运行错误(Virtual MachineError),当JVM不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止;还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError)。这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在Java中,错误通常是使用Error的子类描述。

Exception:在Exception分支中有一个重要的子类RuntimeException(运行时异常),该类型的异常自动为你所编写的程序定义ArrayIndexOutOfBoundsException(数组下标越界)、NullPointerException(空指针异常)、ArithmeticException(算术异常)、MissingResourceException(丢失资源)、ClassNotFoundException(找不到类)等异常,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生;而RuntimeException之外的异常我们统称为非运行时异常,类型上属于Exception类及其子类,从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

throw和throws区别

throw:(针对对象的做法)
抛出一个异常,可以是系统定义的,也可以是自己定义的

public void yichang(){
    NumberFormatException e = new NumberFormatException();
    throw e;
}

throws:(针对一个方法抛出的异常)
抛出一个异常,可以是系统定义的,也可以是自己定义的。

public void yichang() throws NumberFormatException{
    int a = Integer.parseInt("10L");
}
  1. throws出现在方法函数头;而throw出现在函数体。
  2. throws表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某种异常。
  3. 两者都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。

.class 文件是什么类型文件

class文件是一种8位字节的二进制流文件

java中序列化之子类继承父类序列化

父类实现了Serializable,子类不需要实现Serializable

相关注意事项

  1. 序列化时,只对对象的状态进行保存,而不管对象的方法;
  2. 当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
  3. 当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;

并非所有的对象都可以序列化,至于为什么不可以,有很多原因了,比如:

1.安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行rmi传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的。

  1. 资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现。
    2,反过来父类未实现Serializable,子类实现了,序列化子类实例的时候,父类的属性是直接被跳过不保存,还是能保存但不能还原?(答案:值不保存)

解:父类实现接口后,所有派生类的属性都会被序列化。子类实现接口的话,父类的属性值丢失。

java中序列化之子类继承父类序列化

标识符

标识符可以包括这4种字符:字母、下划线、$、数字;开头不能是数字;不能是关键字

Integer i=new Integer(127);和Integer i=127;的区别

Integer i = 127的时候,使用Java常量池技术,是为了方便快捷地创建某些对象,当你需要一个对象时候,就去这个池子里面找,找不到就在池子里面创建一个。但是必须注意 如果对象是用new 创建的。那么不管是什么对像,它是不会放到池子里的,而是向堆申请新的空间存储。Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值在-128到127之间的数时才可使用对象池。超过了就要申请空间创建对象了

    int i1=128;
    Integer i2=128;
    Integer i3=new Integer(128);//自动拆箱
    
    System.out.println(i1==i2);//true
    System.out.println(i1==i3);//true
    
    Integer i5=127;
    Integer i6=127;
    System.out.println(i5==i6);//true
    
    
    Integer i5=127;
    Integer ii5=new Integer(127);
    System.out.println(i5==ii5);//false
    
    Integer i7=new Integer(127);
    Integer i8=new Integer(127);
    System.out.println(i7==i8);//false

手写单例模式

最好的单例模式是静态内部类,不要写双重检验

private static class LazySomethingHolder {
  public static Something something = new Something();
}

public static Something getInstance() {
  return LazySomethingHolder.something;
}

为什么线程通信的方法wait(), notify()和notifyAll()被定义在Object类里?

Java的每个对象中都有一个锁(monitor,也可以成为监视器) 并且wait(),notify()等方法用于等待对象的锁或者通知其他线程对象的监视器可用。在Java的线程中并没有可供任何对象使用的锁和同步器。这就是为什么这些方法是Object类的一部分,这样Java的每一个类都有用于线程间通信的基本方法

Java中wait 和sleep 方法比较

  1. 这两个方法来自不同的类分别是Thread和Object

  2. 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。

  3. wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围)

  4. sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常

  5. sleep方法属于Thread类中方法,表示让一个线程进入睡眠状态,等待一定的时间之后,自动醒来进入到可运行状态,不会马上进入运行状态,因为线程调度机制恢复线程的运行也需要时间,一个线程对象调用了sleep方法之后,并不会释放他所持有的所有对象锁,所以也就不会影响其他进程对象的运行。但在sleep的过程中过程中有可能被其他对象调用它的interrupt(),产生InterruptedException异常,如果你的程序不捕获这个异常,线程就会异常终止,进入TERMINATED状态,如果你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有finally语句块)以及以后的代码。

  • 注意sleep()方法是一个静态方法,也就是说他只对当前对象有效,通过t.sleep()让t对象进入sleep,这样的做法是错误的,它只会是使当前线程被sleep 而不是t线程
  1. wait属于Object的成员方法,一旦一个对象调用了wait方法,必须要采用notify()和notifyAll()方法唤醒该进程;如果线程拥有某个或某些对象的同步锁,那么在调用了wait()后,这个线程就会释放它持有的所有同步资源,而不限于这个被调用了wait()方法的对象。wait()方法也同样会在wait的过程中有可能被其他对象调用interrupt()方法而产生

hashCode和equals方法的关系

在有些情况下,程序设计者在设计一个类的时候为需要重写equals方法,比如String类,但是千万要注意,在重写equals方法的同时,必须重写hashCode方法。
也就是说对于两个对象,如果调用equals方法得到的结果为true,则两个对象的hashcode值必定相等;
如果equals方法得到的结果为false,则两个对象的hashcode值不一定不同;
如果两个对象的hashcode值不等,则equals方法得到的结果必定为false;
如果两个对象的hashcode值相等,则equals方法得到的结果未知。

Object类中有哪些方法

Object是所有类的父类,它有很多类对象会用到的方法

Object方法:equals()、toString()、finalize()、hashCode()、getClass()、clone()、wait()、notify()、notifyAll()

package java.lang;
public class Object {

    private static native void registerNatives();
    static {
        registerNatives();
    }
    // 返回一个对象的运行时类,获得类型的信息。
    public final native Class<?> getClass();
    // 该方法将对象的内存地址进行哈希运算,返回一个int类型的哈希值,是相等对象拥有相同的哈希码,尽量让不等的对象具有不同的哈希码。
    public native int hashCode();
    //指示某个其他对象是否与此对象"相等"。
    public boolean equals(Object obj) {
        return (this == obj);
    }
    //创建并返回此对象的一个副本(复制对象)
    protected native Object clone() throws CloneNotSupportedException;
    //返回该对象的字符串表示。以便用户能够获得一些有关对象状态的基本信息。简单说就是利用字符串来表示对象。
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    //唤醒在此对象监视器上等待的单个线程。
    public final native void notify();
    //唤醒在次对象监视器上等待的所有线程。
    public final native void notifyAll();
    //导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者超过指定的时间量。
    public final native void wait(long timeout) throws InterruptedException;
    //导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
    public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }
        if (nanos > 0) {
            timeout++;
        }
        wait(timeout);
    }
    //导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法。
    public final void wait() throws InterruptedException {
        wait(0);
    }
    //当垃圾回收器确定不存在对该对象的更多引用时,对象的垃圾回收器调用该方法。
    protected void finalize() throws Throwable { }
}

String s=new String(“xyz”)究竟创建String Object分为两种情况

  1. 如果String常理池中,已经创建"xyz",则不会继续创建,此时只创建了一个对象new String(“xyz”);
  2. 如果String常理池中,没有创建"xyz",则会创建两个对象,一个对象的值是"xyz",一个对象new String(“xyz”)。

什么是值传递和引用传递

值传递

public class TempTest {

  private void test1(int a) {
    a = 5;
    System.out.println("test1方法中的a=" + a);
  }

  public static void main(String[] args) {
    TempTest t = new TempTest();
    int a = 3;
    t.test1(11);
    System.out.println("main方法中a=" + a);
  }

}

test1方法中的a=5
main方法中a=3
值传递:传递的是值的拷贝,传递后就互不相关了
引用传递:传递的是变量所对应的内存空间的地址

public class TempTest {
  private void test1(A a) {
    a.age = 20;
    System.out.println("test1方法中a=" + a.age);
  }

  public static void main(String[] args) {
    TempTest t = new TempTest();
    A a = new A();
    a.age = 10;
    t.test1(a);
    System.out.println("main方法中a=" + a.age);
  }
}

class A {
  public int age = 0;
}

test1方法中a=20
main方法中a=20
传递前和传递后都指向同一个引用(同一个内存空间)
如果不互相影响,方法是在test1方法里面新new一个实例就可以了

什么是泛型,为什么要使用以及类型擦除

  1. 泛型的本质就是“参数化类型”,也就是说所操作的数据类型被指定为一个参数。
    创建集合时就指定集合元素的数据类型,该集合只能保存其指定类型的元素,
    避免使用强制类型转换。
  2. Java 编译器生成的字节码是不包含泛型信息的,泛型类型信息将在 编译处理 时
    被擦除,这个过程即 类型擦除。类型擦除可以简单的理解为将泛型 java 代码转
    换为普通 java 代码,只不过编译器更直接点,将泛型 java 代码直接转换成普通
    java 字节码。

类型擦除的主要过程如下:

  1. 将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
  2. 移除所有的类型参数。

什么是序列化?为什么要序列化?

序列化,又称为“串化”,可以形象的把它理解为把Java对象内存中的数据采编成一串二进制的数据,然后把这些数据存放在可以可以持久化的数据设备上,如磁盘。当需要还原这些数据的时候,在通过反序列化的过程,把对象又重新还原到内存中。

为什么要将数据序列化?可以从两个方面来解释,一方面是为了方便数据存储,另一方面是为了方便数据的传递。

序列化好处:

  1. 方便数据传递,减少了数据丢失率,增强了程序安全性。
  2. 有利于数据存储,减少了不必要的内存浪费,节约了资源。
  3. 简化了数据库结构,增强了程序的可维护性。

反射

反射就是动态加载对象,并对对象进行剖析。在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,这种动态获取信息以及动态调用对象方法的功能成为Java反射机制

 Class<?> clz = Class.forName("fs.Student");
 Student stu = (Student) clz.newInstance();

优点

  • 反射提高了程序的灵活性和扩展性,在底层框架中用的比较多,业务层面的开发过程中尽量少用。

缺点

  1. 性能问题。反射包括了一些动态类型,所以 JVM 无法对这些代码进行优化。因此,反射操作的效 率要比那些非反射操作低得多。我们应该避免在经常被 执行的代码或对性能要求很高的程 序中使用反射。
  2. 安全限制。反射要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有 安全限制的环境中运行,如 Applet
  3. 内部暴露。由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方 法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。 反射代码破坏了抽象性。

Java1.0-1.12各个版本的新特性

Version 1.0 1996-01-23 Oak(橡树)

  • 提供了一个解释执行的 Java 虚拟机;
  • Applet 能在 Mozilla 浏览器中运行。

**JDK Version 1.1 1997-02-19 **

  • JDBC(Java DataBase Connectivity);
  • 支持内部类;
  • RMI(Remote Method Invocation) ;
  • 反射;
  • Java Bean;

Java 语言的基本形态基本确定了,比如反射 (reflection), JavaBean, 接口和类的关系等等,一直到今天都保持一致

JDK Version 1.2 1998-12-08 Playground(操场)

  • 集合框架;
  • JIT(Just In Time)编译器;
  • 对打包的Java文件进行数字签名;
  • JFC(Java Foundation Classes), 包括Swing 1.0, 拖放和Java2D类库;
  • Java插件;
  • JDBC中引入可滚动结果集,BLOB,CLOB,批量更新和用户自定义类型;
  • Applet中添加声音支持.

Java 第一个里程碑式的版本。JIT(Just in time)编译器技术,使得语言的可迁移性和执行效率达到最优的平衡,同时 Collections 集合类设计优良,在企业应用开发中迅速得到了广泛使用。

JDK Version 1.3 2000-05-08 Kestrel(红隼)

  • Java Sound API;
  • jar文件索引;
  • 对Java的各个方面都做了大量优化和增强;

JDK Version 1.4 2004-02-06 Merlin(隼)

  • XML处理;
  • Java打印服务;
  • Logging API;
  • Java Web Start;
  • JDBC 3.0 API;
  • 断言;
  • Preferences API;
  • 链式异常处理;
  • 支持IPV6;
  • 支持正则表达式;
  • 引入Imgae I/O API.

Java 语言真正走向成熟,提供了非常完备的语言特性,如 NIO,正则表达式,XML 处理器等。

JAVA 5 2004-09-30 Tiger(老虎)

  • 泛型;
  • 增强循环,可以使用迭代方式;
  • 自动装箱与自动拆箱;
  • 类型安全的枚举;
  • 可变参数;
  • 静态引入;
  • 元数据(注解);
  • Instrumentation;

这个版本发生很大的变化,如注解 (Annotation),装箱 (Autoboxing),泛型 (Generic),枚举 (Enum),foreach 等被加入,提供了 java.util.concurrent 并发包。

JAVA 6 2006-12-11 Mustang(野马)

  • 支持脚本语言;
  • JDBC 4.0API;
  • Java Compiler API;
  • 可插拔注解;
  • 增加对Native PKI(Public Key Infrastructure), Java GSS(Generic Security Service),Kerberos和LDAP(Lightweight Directory Access Protocol)支持;
  • 继承Web Services;

JAVA 7 2011-07-28 Dolphin(海豚)

  • switch语句块中允许以字符串作为分支条件;
  • 在创建泛型对象时应用类型推断;
  • 在一个语句块中捕获多种异常;
  • 支持动态语言;
  • 支持try-with-resources(在一个语句块中捕获多种异常);
  • 引入Java NIO.2开发包;
  • 数值类型可以用二进制字符串表示,并且可以在字符串表示中添加下划线;
  • 钻石型语法(在创建泛型对象时应用类型推断);
  • null值得自动处理;

这个版本中最引人注目的便是 NIO2 和 Fork/Join 并发包

JAVA 8 2014-03-18

  • Lambda 表达式 − Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中。
  • 方法引用 − 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
  • 默认方法 − 默认方法就是一个在接口里面有了一个实现的方法。
  • 新工具 − 新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
  • Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
  • Date Time API − 加强对日期与时间的处理。
  • Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
  • Nashorn, JavaScript 引擎 − Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。

这个版本中最引人注目的便是 Lambda 表达式了,从此 Java 语言原生提供了函数式编程能力

JAVA 9 2017-09-22

  • 模块系统:模块是一个包的容器,Java 9 最大的变化之一是引入了模块系统(Jigsaw 项目)。
  • REPL (JShell):交互式编程环境。
  • 默认的垃圾回收器 —— G1
  • HTTP 2 客户端:HTTP/2标准是HTTP协议的最新版本,新的 HTTPClient API 支持 WebSocket 和 HTTP2 流以及服务器推送特性。
  • 改进的 Javadoc:Javadoc 现在支持在 API 文档中的进行搜索。另外,Javadoc 的输出现在符合兼容 HTML5 标准。
  • 多版本兼容 JAR 包:多版本兼容 JAR 功能能让你创建仅在特定版本的 Java 环境中运行库程序时选择使用的 class 版本。
  • 集合工厂方法:List,Set 和 Map 接口中,新的静态工厂方法可以创建这些集合的不可变实例。
  • 私有接口方法:在接口中使用private私有方法。我们可以使用 private 访问修饰符在接口中编写私有方法。
  • 进程 API: 改进的 API 来控制和管理操作系统进程。引进 java.lang.ProcessHandle 及其嵌套接口 Info 来让开发者逃离时常因为要获取一个本地进程的 PID 而不得不使用本地代码的窘境。
  • 改进的 Stream API:改进的 Stream API 添加了一些便利的方法,使流处理更容易,并使用收集器编写复杂的查询。
  • 改进 try-with-resources:如果你已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources 语句中使用该变量,而无需在 try-with-resources 语句中声明一个新变量。
  • 改进的弃用注解 @Deprecated:注解 @Deprecated 可以标记 Java API 状态,可以表示被标记的 API 将会被移除,或者已经破坏。
  • 改进钻石操作符(Diamond Operator) :匿名类可以使用钻石操作符(Diamond Operator)。
  • 改进 Optional 类:java.util.Optional 添加了很多新的有用方法,Optional 可以直接转为 stream。
  • 多分辨率图像 API:定义多分辨率图像API,开发者可以很容易的操作和展示不同分辨率的图像了。
  • 改进的 CompletableFuture API : CompletableFuture 类的异步机制可以在 ProcessHandle.onExit 方法退出时执行操作。
  • 轻量级的 JSON API:内置了一个轻量级的JSON API
  • 响应式流(Reactive Streams) API: Java 9中引入了新的响应式流 API 来支持 Java 9 中的响应式编程。

这个版本中最引人注目的时候模块化和默认垃圾回收器G1,通过这个工作,可以构建更小的运行时环境,只需要包括Java平台中任务依赖的部分。这可以更好地适应云端的开发。

JAVA 10 2018-03-21

  • JEP286: var 局部变量类型推断。
  • JEP296: 将原来用 Mercurial 管理的众多 JDK 仓库代码,合并到一个仓库中,简化开发和管理过程。
  • JEP304: 统一的垃圾回收接口。
  • JEP307: G1 垃圾回收器的并行完整垃圾回收,实现并行性来改善最坏情况下的延迟。
  • JEP310: 应用程序类数据 (AppCDS) 共享,通过跨进程共享通用类元数据来减少内存占用空间,和减少启动时间。
  • JEP312: ThreadLocal 握手交互。在不进入到全局 JVM 安全点 (Safepoint) 的情况下,对线程执行回调。优化可以只停止单个线程,而不是停全部线程或一个都不停。
  • JEP313: 移除 JDK 中附带的 javah 工具。可以使用 javac -h 代替。
  • JEP314: 使用附加的 Unicode 语言标记扩展。
  • JEP317: 能将堆内存占用分配给用户指定的备用内
  • JEP317: 使用 Graal 基于 Java 的编译器,可以预先把 Java 代码编译成本地代码来提升效能。
  • JEP318: 在 OpenJDK 中提供一组默认的根证书颁发机构证书。开源目前 Oracle 提供的的 Java SE 的根证书,这样 OpenJDK 对开发人员使用起来更方便。
  • JEP322: 基于时间定义的发布版本,即上述提到的发布周期。版本号为$FEATURE.$INTERIM.$UPDATE.$PATCH,分j别是大版本,中间版本,升级包和补丁版本。

JAVA 11 2018-09-25

  • 181:Nest-Based访问控制
  • 309:动态类文件常量
  • 315:改善Aarch64 intrinsic
  • 318:无操作垃圾收集器
  • 320:消除Java EE和CORBA模块
  • 321:HTTP客户端(标准)
  • 323:局部变量的语法λ参数
  • 324:Curve25519和Curve448关键协议
  • 327:Unicode 10
  • 328:飞行记录器
  • 329:ChaCha20和Poly1305加密算法
  • 330:发射一列纵队源代码程序
  • 331:低开销堆分析
  • 332:传输层安全性(Transport Layer Security,TLS)1.3
  • 333:动作:一个可伸缩的低延迟垃圾收集器 (实验)
  • 335:反对Nashorn JavaScript引擎
  • 336:反对Pack200工具和API

**JAVA 12 2018-09-25 **

  • 189: Shenandoah: A Low-Pause-Time Garbage Collector (Experimental) :新增一个名为 Shenandoah 的垃圾回收器,它通过在 Java 线程运行的同时进行疏散
    (evacuation) 工作来减少停顿时间。
  • 230: Microbenchmark Suite:新增一套微基准测试,使开发者能够基于现有的 Java Microbenchmark Harness(JMH)轻松测试 JDK 的性能,并创建新的基准测试。
  • 325: Switch Expressions (Preview) :对 switch 语句进行扩展,使其可以用作语句或表达式,简化日常代码。
  • 334: JVM Constants API :引入一个 API 来对关键类文件 (key class-file) 和运行时工件的名义描述(nominal descriptions)进行建模,特别是那些可从常量池加载的常量。
  • 340: One AArch64 Port, Not Two :删除与 arm64 端口相关的所有源码,保留 32 位 ARM 移植和 64 位 aarch64 移植。
  • 341: Default CDS Archives :默认生成类数据共享(CDS)存档。
  • 344: Abortable Mixed Collections for G1 :当 G1 垃圾回收器的回收超过暂停目标,则能中止垃圾回收过程.
  • 346: Promptly Return Unused Committed Memory from G1 :改进 G1 垃圾回收器,以便在空闲时自动将 Java 堆内存返回给操作系统。

Long.ValueOf(“String”)与Long.parseLong(“String”)的区别

Long.ValueOf(“String”)返回Long包装类型

Long.parseLong(“String”)返回long基本数据类型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

终极之旅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值