(0)Java由来
- 1991年1月 Green Project启动,致力于家用电器智能化。
- 1991年2月 James Gosling作为Green Project的软件负责人开始选择C++作为开发语言,最后发现C++不能满足需要,所以决定开发一门新语言,取名Oak。
- 1991年4月 Ed Frank加入Green Project领导硬件开发,组建Star-seven (*7) Project目的是开发一个硬件原型,展示Green Project的功能。
- 1991年6月 James Gosling开始编写Oak解释器。
- 1992年3月 由于Oak已经被另一门语言使用,改名为Java。
- 1992年9月 James Gosling亲自用PDA样机演示Star-seven (*7) https://www.youtube.com/watch?v=1CsTH9S79qI
- 1992年11月 Green project从Sun公司独立出来成立FirstPerson。
- 1993年2月 由于Green Project不是很成功,FirstPerson失去了时代华纳的机顶盒交互系统订单。开发重心从家庭消费电子产品转到了电视盒机顶盒的相关平台上。
- 1993年9月 Arthur Van Hoff加入,致力于交互平台上的应用开发。
- 1994年6月 FirstPerson解散,所有人回归Sun。启动Liveoak,使用Oak开发一个新的操作系统。
- 1994年7月 Patrick Naughton做了一个浏览器Era可以使Java在里边运行,Liveoak计划进行了调整,使得Oak语言支持互联网。
- 1994年9月 Naughton和Jonatha Payne做了一个基于Java的浏览器HotJava(开始叫WebRunner),获得了管理层的广泛认可。
- 1994年10月 Arthur Van Hoff使用Java编写了Java compiler,之前James Gosling使用C写的。
(1)JDK Alpha and Beta (1995)
- 1995年5月23日 在SunWorld Conference上Sun正式发布Java 1.0α和HotJava,这一年Windows95和IE 1.0发布(微软的巅峰时代)
- 1995年6月 Netscape浏览器支持Java
- 1995年10月 Java 1.0β发布
- 1995年12月 Microsoft在IE中支持Java
Sun的slogan“Write once, run anywhere”,但最开始Java存在大量问题,变成了“Write once,debug everything”。同时期(95-96)的语言还有:JS、Ruby、PHP、Delphi、ColdFusion、OCaml、Ada95。
(3)Java 1.1(JDK1.1) (1997/02/19) Sparkler
Sparkler (v1.1.4), Pumpkin (v1.1.5), Abigail (v1.1.6), Brutus (v1.1.7) and Chelsea (v1.1.8)。
Microsoft推出J++(实现了函数指针,C#前身),扯不尽的官司。
内部类Inner Class
public class InnerClassSample extends java.applet.Applet { public class ApproceListner implements ActionListener { // 内部类 public void actionPerformed(final ActionEvent e) { } } public void init() { Button approveButton = new Button("OK"); approveButton.addActionListener(new ApproceListner()); this.add(approveButton); } }
匿名类Anonymous Class
public class AnonymousClassSample extends java.applet.Applet { public void init() { Button approveButton = new Button("OK"); approveButton.addActionListener(new ActionListener() { // 匿名类 public void actionPerformed(final ActionEvent e) { } }); this.add(approveButton); } }
类字面常量Class literal (广发用于反射和泛型)
// 用于反射和泛型 final Class a = List.class; final Class b = String.class; final Class c = double.class; final Class d = int[][].class;
反射Reflection(Introspection only)
BeanInfo bi = Introspector.getBeanInfo(Class.forName("com.rensanning.java.feature.jdk1_1.Rectangle")); PropertyDescriptor props[] = bi.getPropertyDescriptors(); for (int i = 0; i < props.length; i++) { PropertyDescriptor pd = props[i]; System.out.println( pd.getName()+" "+pd.getPropertyType()+" "+ pd.getReadMethod()+"/"+pd.getWriteMethod() ); } System.out.println("------------"); MethodDescriptor methods[] = bi.getMethodDescriptors(); for (int i = 0; i < methods.length; i++) { MethodDescriptor md = methods[i]; System.out.println(md.getMethod().toString()); }
数据库连接JDBC (Java Database Connectivity)
引用
JDK 1.1 = JDBC 1.0
JDK 1.2 = JDBC 2.0
JDK 1.4 = JDBC 3.0
JDK6 = JDBC 4.0
JDK7 = JDBC 4.1
JDK 1.2 = JDBC 2.0
JDK 1.4 = JDBC 3.0
JDK6 = JDBC 4.0
JDK7 = JDBC 4.1
// Loading and Registering Drivers Class.forName("oracle.jdbc.driver.OracleDriver"); // Connecting to a Database Connection con = DriverManager.getConnection( "jdbc:oracle:thin:@localhost:1521:ug", "username", "password"); // Creating and Executing Statements Statement stmt = con.createStatement(); // Executing Inserts, Updates, and Deletes int rowCount = stmt.executeUpdate("INSERT INTO branch VALUES (20, 'Richmond Main', " + "'18122 No.5 Road', 'Richmond', 5252738)"); // Executing Queries ResultSet rs = stmt.executeQuery("SELECT * FROM branch"); while(rs.next()) { branchID = rs.getInt(1); branchName = rs.getString("branch_name"); branchAddr = rs.getString(3); branchCity = rs.getString("branch_city"); branchPhone = rs.getInt(5); . . . } // Close resources rs.close(); stmt.close(); con.close();
JavaBeans、RMI (Remote Method Invocation) (也叫RPC) EJB的基础
public class RmiSample { public static void main(String[] args) throws Exception { System.setProperty("java.rmi.server.hostname", "127.0.0.1"); new RmiServer(); new RmiClient(); } } interface Rmi extends Remote { public String getMessage() throws RemoteException; } class RmiImpl implements Rmi, Serializable { @Override public String getMessage() throws RemoteException { return "RmiImpl#message"; } } class RmiServer { public RmiServer() throws RemoteException { Remote r = createObject(); regist(r); } Remote createObject() throws RemoteException { Rmi rs = new RmiImpl(); Remote r = UnicastRemoteObject.exportObject(rs, 0); return r; } void regist(Remote r) throws RemoteException { // 默认端口是1099:Registry.REGISTRY_PORT Registry registry = LocateRegistry.createRegistry(9527); registry.rebind("RmiName", r); } } class RmiClient { public RmiClient() throws Exception { Rmi rs = lookup(); System.out.println(rs.getMessage()); } Rmi lookup() throws MalformedURLException, RemoteException, NotBoundException { Remote r = Naming.lookup("//127.0.0.1:9527/RmiName"); return (Rmi) r; } }
(4)J2SE 1.2(J2SDK1.2) (1998/12/08) Playground
集合框架Collections Framework
// 旧写法(JDK1.1) Vector v = new Vector(); v.addElement("1"); v.addElement("2"); v.addElement("3"); Enumeration e = v.elements(); while (e.hasMoreElements()) System.out.println(e.nextElement()); v.removeElement("1"); int n = v.size(); for (int i = 0; i < n; i++) System.out.println(v.elementAt(i)); // 新写法(JDK1.2) List l = new ArrayList(); l.add("1"); l.add("2"); l.add("3"); Iterator it = l.iterator(); while (it.hasNext()) System.out.println(it.next()); l.remove("1"); int s = l.size(); for (int i = 0; i < s; i++) System.out.println(l.get(i));
基础图形库Java Foundation Classes (JFC) 包含Swing、AWT、Java2D********** 《Java Swing》
(5)J2SE 1.3(J2SDK1.3) (2000/05/08) Kestrel
动态代理Dynamic Proxy(用于Spring等AOP/DI框架、EasyMock等mock框架)
public class DynamicProxySample { public static void main(String[] args) { MyInterface myInterfaceReal = new MyClass(); InvocationHandler handler = new MyInvocationHandler(myInterfaceReal); MyInterface myInterface = (MyInterface) Proxy.newProxyInstance( MyClass.class.getClassLoader(), MyClass.class.getInterfaces(), handler); String ret = myInterface.sayHello("JAVA"); System.out.println(ret); } } class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("invoke method:" + method.getName()); Object ret = method.invoke(this.target, args); System.out.println("invoke result:" + ret.toString()); return ret; } } interface MyInterface { String sayHello(String name); } class MyClass implements MyInterface { public String sayHello(String name) { System.out.println("hello! " + name); return "hello!"; } }
声音接口Java Sound
// Simple Audio Player URL soundFile = new URL("http://www.wav-sounds.com/cartoon/bugsbunny1.wav"); AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(soundFile); AudioFormat audioFormat = audioInputStream.getFormat(); DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat); SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info); line.open(audioFormat); line.start(); int nBytesRead = 0; byte[] abData = new byte[128000]; while (nBytesRead != -1) { try { nBytesRead = audioInputStream.read(abData, 0, abData.length); } catch (IOException e) { e.printStackTrace(); } if (nBytesRead >= 0) { line.write(abData, 0, nBytesRead); } } line.drain(); line.close();
(6)J2SE 1.4(J2SDK1.4) (2002/2/6-2008/10) Merlin JSR 59
1998年成立的JCP发布的第一版本
断言Assertions
int i = 1; // OK assert i == 1; System.out.println("1"); // AssertionError assert i == 2 : "i = "+ i; System.out.println("2");
正则表达式Regular Expressions
Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(input); if (matcher.matches()) { System.out.println("[" + input + "] matches [" + pattern.pattern() + "]"); } else { System.out.println("[" + input + "] DON'T matches [" + pattern.pattern() + "]"); }
新的输入与输出操作New I/O*********** 《Java NIO》
String text = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; try { FileOutputStream stream = new FileOutputStream("c://test.txt"); FileChannel channel = stream.getChannel(); byte[] bytes = text.getBytes(); ByteBuffer buffer = ByteBuffer.wrap(bytes); channel.write(buffer); channel.close(); stream.close(); } catch (Exception ex) { ex.printStackTrace(); }
链式异常Chained Exception
public static void test() throws TestException { try { throw new InterruptedException(); } catch (InterruptedException ex) { throw new TestException(ex); } }
日志接口Logging API
Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); logger.info("info"); logger.warning("warning"); logger.severe("severe");
图像接口Image I/O API
String sourceFile = "c://test.jpg"; String destinationFile = "c://test-new.png"; File source = new File(sourceFile); File dest = new File(destinationFile); String extension = getSuffix(destinationFile); try { BufferedImage image = ImageIO.read(source); ImageIO.write(image, extension, dest); } catch (IOException ex) { ex.printStackTrace(); }
打印Print Service
URL url = new URL("https://www.baidu.com/img/bdlogo.png"); DocFlavor docFlavor = DocFlavor.URL.PNG; Doc doc = new SimpleDoc(url, docFlavor, null); PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet(); attrs.add(new Copies(1)); attrs.add(MediaSizeName.ISO_A4); PrintService[] printServices = PrintServiceLookup.lookupPrintServices(docFlavor, attrs); PrintService printService = ServiceUI.printDialog(null, 100, 100, printServices, printServices[0], docFlavor, attrs); if (printService == null) { return; } printService.createPrintJob().print(doc, attrs);
(7)J2SE 5.0(JDK5.0) (2004/9/30-2009/10) Tiger JSR 176
泛型Generics********** 《Java Generics》
public class GenericSample { public static void main(String[] args) { // 实例生成时指定类型 MyClass<String, String> mc = new MyClass<String, String>(); mc.setKeyValue("1", "test"); String key = mc.getKey(); System.out.println("key = " + key); } } class MyClass<K, V> { private K key; private V value; public void setKeyValue(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } }
枚举Enums
// 旧写法 public static final int APPLE = 0; public static final int ORANGE = 1; public static final int GRAPE = 2; // 新写法 enum Fruit { APPLE, ORANGE, GRAPE } public static void main(String[] args) { Fruit fruit = Fruit.ORANGE; if (fruit == Fruit.GRAPE) { System.out.println("fruit is " + Fruit.GRAPE); } else { System.out.println("fruit is not " + Fruit.GRAPE); } }
注解Annotations (Metadata) 便于编译器在编译期根据Metadata做各种各样的校验;第三方框架或工具根据Metadata生成代码、文档等,实现DI等。比如:Override、Deprecated、SuppressWarnings
@StringAnnotation("Class") public class AnnotationSample { @StringAnnotation("Constructor") public AnnotationSample() { } @StringAnnotation("Field") public int n; @StringAnnotation("Method") public void function( @StringAnnotation("Param1") int param1, @StringAnnotation("Param2") int param2) { } public static void main(String[] args) { Class clazz = AnnotationSample.class; p("类", clazz.getDeclaredAnnotations()); Constructor[] cs = clazz.getConstructors(); p("构造函数", cs[0].getDeclaredAnnotations()); Field[] fs = clazz.getDeclaredFields(); p("成员变量", fs[0].getDeclaredAnnotations()); Method[] ms = clazz.getDeclaredMethods(); p("方法", ms[1].getDeclaredAnnotations()); Annotation[][] ma = ms[1].getParameterAnnotations(); p("参数1", ma[0]); p("参数2", ma[1]); } public static void p(String message, Annotation[] as) { System.out.println(message); for (Annotation a : as) { System.out.println(a); } } } @Retention(RetentionPolicy.RUNTIME) @interface StringAnnotation { String value(); }
增强循环Enhanced for Loop
List<Integer> list = new ArrayList<Integer>(); list.add(2); // 旧写法 Iterator<Integer> it = list.iterator(); while (it.hasNext()) { System.out.println(it.next()); } // 新写法 for (Integer value : list) { System.out.println(value); }
自动装解箱Autoboxing/Unboxing
List<Integer> list = new ArrayList<Integer>(); // 旧写法 list.add(new Integer(1)); int x = list.get(0).intValue(); // 新写法 list.add(2); int y = list.get(1); System.out.println("x = " + x); System.out.println("y = " + y);
变参Varargs
public static void variableLengthArgument(String... args) { for (String arg : args) { System.out.println(arg); } }
静态引入Static Import
import static java.lang.Math.*; public class StaticImportSample { public static void main(String[] args) { // 旧写法 System.out.println("cos(PI) = "+ Math.cos(Math.PI)); // 新写法 System.out.println("cos(PI) = "+ cos(PI)); } }
并发库Concurrency Framework********** 《Java Concurrency In Practice》
(8)Java SE 6(JDK6) (2006/12/11-2013/2) Mustang JSR 270
语言本身变化不大
脚本语言支持Scripting Language Support
ScriptEngineManager factory = new ScriptEngineManager(); ScriptEngine engine = factory.getEngineByName("JavaScript"); String script = "function hello (name) {return 'Hello,' + name;}"; engine.eval(script); Invocable inv = (Invocable) engine; String res = (String) inv.invokeFunction("hello", "Scripting"); System.out.println("res:" + res);
编译器接口Java Compiler API
public class CompilerAPISample { public static void main(String[] args) { JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); String src = "public class HelloWorld {" + "public static int main(String args[]) {" + "System.out.println(\"This is in another java file\");" + "return(1);" + "}" + "}"; JavaFileObject file = new JavaSourceFromString("HelloWorld", src); String[] compileOptions = new String[] { "-d", "bin" }; Iterable<String> compilationOptionss = Arrays.asList(compileOptions); Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file); CompilationTask task = compiler.getTask(null, null, diagnostics, compilationOptionss, null, compilationUnits); boolean success = task.call(); System.out.println("Success: " + success); if (success) { Object ret; try { Class<?> clazz = Class.forName("HelloWorld"); Method method = clazz.getMethod("main", new Class[] { String[].class }); ret = method.invoke(null, new Object[] { null }); System.out.println(ret); } catch (Exception e) { e.printStackTrace(); } } } } class JavaSourceFromString extends SimpleJavaFileObject { final String code; JavaSourceFromString(String name, String code) { super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); this.code = code; } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) { return code; } }
JAXB
public class JAXBSample { public static void main(String[] args) { Book book = new Book(); book.setAuthor("rensanning"); book.setTitle("Java New Feature"); book.setPages(88); File file = new File("c://testJAXB.xml"); try { JAXBContext ctx = JAXBContext.newInstance(Book.class); Marshaller marshaller = ctx.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(book, file); marshaller.marshal(book, System.out); Unmarshaller unmarshaller = ctx.createUnmarshaller(); Book xmlBook = (Book) unmarshaller.unmarshal(file); System.out.println(xmlBook); } catch (JAXBException e) { e.printStackTrace(); } } } @XmlRootElement class Book { private String title; private String author; private int pages; public String getTitle() { return title; } @XmlAttribute public void setTitle(String name) { this.title = name; } public String getAuthor() { return author; } @XmlElement public void setAuthor(String author) { this.author = author; } public int getPages() { return pages; } @XmlElement public void setPages(int pages) { this.pages = pages; } @Override public String toString() { return "Book [title=" + title + ", author=" + author + ", pages=" + pages + "]"; } }
其他
public class HTTPServerSample { public static void main(String[] args) throws IOException { HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0); server.createContext("/sample", new SampleHandler()); server.setExecutor(null); server.start(); } } class SampleHandler implements HttpHandler { public void handle(HttpExchange exchange) throws IOException { String response = "Hello World"; exchange.sendResponseHeaders(200, response.length()); OutputStream ost = exchange.getResponseBody(); ost.write(response.getBytes()); ost.close(); } }
public class ArrayCopySample { public static void main(String[] args) { // 前几项 final String[] original = {"Java", "Scala", "F#", "C#", "Haskell", "Python"}; final String[] first3 = Arrays.copyOf(original, 3); // 任意区间 final int[] original2 = {0, 10, 20, 30, 40, 50}; final int[] range = Arrays.copyOfRange(original2, 3, 5); } }
(9)Java SE 7(JDK7) (2011/7/28-2015/4) Dolphin JSR 336
二进制字面量和数字字面量下划线支持Binary Literals, Underscores in Numeric Literals
byte b = 0b010101; short s = 0b010101010101; int i = 0B010101010101010101010101; long l = 0B0101010101010101010101010101010101010101L; byte bb = 0b0101_0101; short ss = 0x1F_2E; int ii = 1_234_567_890;
switch中支持字符串Strings in switch Statements
String text = "ren"; switch (text) { case "zhang": System.out.println("zhang"); break; case "ren": System.out.println("ren"); break; default: System.out.println("none"); break; }
同时捕获多个异常处理Catching Multiple Exception Types and Rethrowing Exceptions with Improved Type Checking
public class MultiCatchSample { public static void main(String[] args) throws Exception { multiCatch(); System.out.println("-------------------"); rethrow("aaa"); } public static void multiCatch() { try { Field field = String.class.getField("equals111"); System.out.println(field); // 多个异常时用竖线隔开 } catch (NoSuchFieldException | SecurityException e) { e.printStackTrace(); } } public static void rethrow(String name) throws NoSuchFieldException, SecurityException { try { if (name.equals("First")) { throw new NoSuchFieldException(); } else { throw new SecurityException(); } } catch (Exception e) { // 捕获后原封不动在throw throw e; } } }
泛型实例创建的类型推断Type Inference for Generic Instance Creation Diamond Syntax
// 旧写法 List<String> oldList = new ArrayList<String>(); Map<String, Long> oldMap = new HashMap<String, Long>(); List<Map<String, Long>> oldListMap = new ArrayList<Map<String, Long>>(); // 新写法 List<String> newList = new ArrayList<>(); Map<String, Long> newMap = new HashMap<>(); List<Map<String, Long>> newListMap = new ArrayList<>();
自动资源管理The try-with-resources Statement
public class TryWithResourcesSample { public static void main(String[] args) { // 多个可以用逗号隔开 try (MyFileReader auto1 = new MyFileReader(); MyFileReader auto2 = new MyFileReader()) { System.out.println("Processing!"); } catch (Exception e) { e.printStackTrace(); } } } class MyFileReader implements AutoCloseable { @Override public void close() throws Exception { System.out.println("Close!"); } }
对动态语言的支持Support fro Dynamic Language(InvokeDynamic)
MethodHandles.Lookup lookup = MethodHandles.lookup(); String name; MethodType methodType; MethodHandle methodHandle; // Lookup invoke dynamic methodType = MethodType.methodType(String.class); methodHandle = lookup.findVirtual(Employee.class, "getName", methodType); name = (String) methodHandle.invokeExact(new Employee()); System.out.println("invoke dynamic " + name); // Lookup reflection Method method = Employee.class.getMethod("getName", new Class[]{}); name = (String) method.invoke(new Employee()); System.out.println("reflection " + name);
NIO2********** 《Pro Java 7 NIO.2》
public static void nio2Directory() throws Exception { DirectoryStream<Path> stream = Files.newDirectoryStream( Paths.get("c://"), new DirectoryStream.Filter<Path>() { @Override public boolean accept(final Path entry) throws IOException { return !Files.isDirectory(entry); } }); for (Path p : stream) { System.out.println(p.getFileName()); } } public static void nio2Files() throws Exception { Path sampleFilePath = Paths.get("sample.txt"); if (!Files.notExists(sampleFilePath)) { return; } sampleFilePath = Files.createFile(Paths.get("sample.txt")); String content = "line1\nline2\n"; Files.write(sampleFilePath, content.getBytes()); for (String line : Files.readAllLines(sampleFilePath, Charset.defaultCharset())) { System.out.println(line); } System.out.println(Files.deleteIfExists(sampleFilePath)); }
(10)Java SE 8(JDK8) (2014/3/18-2017/3) JSR 337
- Lambda表达式Lambda Expressions 详细内容
- 默认方法、函数式接口、方法引用Method References、Default Methods、Type Inference 详细内容
- 流Stream 详细内容
- 新日期时间接口Date and Time API 详细内容
(11)Java SE 9 (2017?)
Jigsaw:模块化JDK
Kulla:REPL (JShell)
接口private method
......
Java 9 Features with Examples
关于Java的interface
最开始只能是public abstract method / public static final variable,所以方法或变量前不用写修饰符。
Java 8开始支持 public static method 和 public default method
Java 9开始支持 private static method 和 private method
Java版本命名:
- •Java Platform 1.1.X_YYY
- •J2SE 1.2.X_YYY
- •J2SE 1.3.X_YY
- •J2SE 1.4.X_YY
- •J2SE 5.X Update Y (5.0u22)
- •JavaSE 6 Update Y (6u45)
- •JavaSE 7 Update Y (7u76)
- •JavaSE 8 Update Y (8u40)
JVM实现:
- •HotSpot VM(Sun Microsystems公司开发)
- •JRockit VM(BEA Systems公司开发,针对Intel CPU和服务器,WebLogic Server中用)
- •IBM J9 VM
- •Dalvik VM
- •其他
***Oracle收购BEA Systems和Sun Microsystems后就同时拥有了前两个VM。
JDK的实现:
- •Sun Java(Oracle Java)
- •IBM JDK
- •OpenJDK
***Eclipse中JDT (Eclipse Java development tools) 使用的的Java编译器不是OpenJDK也不是OracleJDK而是Eclipse自己做的ECJ (Eclipse Compiler for Java)。
其他相关问题
- •Java 2:和JDK1.1区别从「Java 2 SDK 1.2.2_004」开始称Java2,Java 2(J2ME、J2SE、J2EE三个版本开始出现)。
- •Oracle收购Sun后把http://java.sun.com/重定向到http://www.oracle.com/technetwork/java/index.html以前很多文档都看不到了。
- •搜JDK的源码发现很多类已经找不到原来的作者了,它们被标记为“@author unascribed”,其中不乏我们常用的System、File、Thread、Socket、IOException、NullPointerException、FileNotFoundException等。
- 2006年11月 Java开源但是争议很大被称为半开源
- 2007年11月5日 谷歌发布Android操作系统
- 2010年1月 Oracle收购Sun
- 2010年10月 乔布斯宣布Apple不再支持Java
参考:
http://en.wikipedia.org/wiki/Java_(programming_language)
http://docs.oracle.com/javase/specs/
http://oracle.com.edgesuite.net/timeline/java/
http://docs.oracle.com/javase/8/docs/technotes/guides/language/enhancements.html
http://javapapers.com/core-java/java-features-and-history/
http://javapapers.com/core-java/java-history/
http://www.ne.jp/asahi/hishidama/home/tech/java/uptodate.html