1. 基本概念
面向对象(封装、继承、多态)
由于jvm的存在,Java和平台无关,一次编译,多地运行
编译和解释并存:Java源码→(javac编译)→.class字节码→(JVM解释)→机器码
为了加速解释过程,引入运行时编译,即JIT,当 JIT 编译器完成第一次编译后,会将字节码对应的机器码保存下来,下次可以直接使用。
支持网络编程和多线程,能很方便地编写出多线程程序和网络程序。
自动内存管理,无需像C++一样要手动管理内存。
2. 数据结构 2.1 Java容器之间的区别 (1)ArrayList、Vector、LinkedList的区别?
都实现了 List
接口,用来存储有序、可重复的数据
ArrayList
是List
的主要实现类,底层采用Object[]
存储,线程不安全,效率高。
Vector
是List
的古老实现类,底层采用Object[]
存储,线程安全,效率低。
LinkedList
底层采用双向链表存储,线程不安全。
(2)HashSet、LinkedHashSet、HashTree的区别?
都实现了 Set
接口,用来存储无序、不可重复的数据
HashSet
: Set
接口的主要实现类,线程不安全,可存储 null
LinkedHashSet
:HashSet
的子类,遍历其内部数据时,可以按照添加的顺序遍历。每个节点处理包含自身数据,还记录了前一个数据和后一个数据的应用,在频繁遍历时效率高
TreeSet
:可以按照添加元素的指定属性进行排序,元素必须是同一个类,底层采用红黑树
(3)HashMap、HashTable、TreeMap的区别?
HashMap
: Map
的主要实现类,线程不安全,效率高,可以存储 null
, jdk7 之前底层时数组+链表, jdk8 采用数组+链表+红黑树,具体为:当数组中某一个索引位置上的以链表形式存在的元素个数>8且当前数组长度>64时,改用数组+红黑树存储
LinkedHashMap
:在遍历元素时,可以按照添加顺序遍历,每个节点多了一对指针,指向前一个和后一个元素,适合频繁的遍历操作。
HashTable
: Map
的古老实现类,线程安全,效率低,不能存储null
Prosperities
:常用来处理配置文件, Key 和 Value 都是 String 类型
TreeMap
:可以按照Key值进行排序
(4)自定义类需要重写的方法
HashSet、LinkedHashSet
TreeSet
如果要自定义排序:Comparable、Comparator
2.2 Java int[] 和 List<> 的相互转换 1 2 3 4 5 6 Integer [] myArray = { 1 , 2 , 3 }; List myList = Arrays.stream(myArray).collect(Collectors.toList()); int [] myArray2 = { 1 , 2 , 3 };List myList = Arrays.stream(myArray2).boxed().collect(Collectors.toList());
1 2 List list = new ArrayList<>(Arrays.asList("a" , "b" , "c" ))
1 2 3 4 5 6 7 8 9 10 List<String> il = ImmutableList.of("string" , "elements" ); List<String> il = ImmutableList.copyOf(aStringArray); List<String> l1 = Lists.newArrayList(anotherListOrCollection); List<String> l2 = Lists.newArrayList(aStringArray); List<String> l3 = Lists.newArrayList("or" , "string" , "elements" );
不要在 foreach 循环里进行元素的 remove/add 操作
2.3 String类和常量池 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Test void test () { String str1 = "abcd" ; String str2 = new String("abcd" ); String str3 = new String("abcd" ); String str4 = new StringBuilder("ab" ).append("cd" ).toString(); String str5 = new StringBuilder("ab" ).append("cd" ).toString(); String str6 = new StringBuilder("ab" ).append("cd" ).toString().intern(); System.out.println("str1:" + System.identityHashCode(str1)); System.out.println("str2:" + System.identityHashCode(str2)); System.out.println("str3:" + System.identityHashCode(str3)); System.out.println("str4:" + System.identityHashCode(str4)); System.out.println("str5:" + System.identityHashCode(str5)); System.out.println("str6:" + System.identityHashCode(str6)); }
只要使用 new 方法,便需要创建新的对象。
intern()方法:如果运行时常量池中已经包含一个等于此 String 对象内容的字符串,则返回常量池中该字符串的引用;如果没有,JDK1.6及之前的处理方式是在常量池中创建 与此 String 内容相同的字符串,并返回常量池中创建的字符串的引用,JDK1.7及之后的处理方式是在常量池中记录 此字符串的引用,并返回该引用。
3. 多线程 3.1 基本概念
程序(program):一段静态的代码。
进程(process):正在运行的一个程序。是资源分配的单位 。
线程(thread):进程可进一步细化为线程,是一个程序内部的一条执行路径。是调度和执行的单位 。
3.2 线程的创建和使用
方法一:继承 Thread
类1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class MyThread extends Thread { @Override public void run () { System.out.println("sub thread: " + Thread.currentThread().getName()); } } class MyThreadTest { @Test void test () { MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); t1.start(); t2.start(); System.out.println("main thread: " + Thread.currentThread().getName()); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class MyRunnable implements Runnable { @Override public void run () { System.out.println(Thread.currentThread().getName()); } } class MyRunnableTest { @Test void test () { MyRunnable runnable = new MyRunnable(); Thread t1 = new Thread(runnable); Thread t2 = new Thread(runnable); Thread t3 = new Thread(runnable); t1.start();t2.start();t3.start(); try { t1.join();t2.join();t3.join(); } catch (InterruptedException e) { e.printStackTrace(); } } }
方法三:实现 Callable
接口(新)
重写 call()
方法,相比 run()
方法,可以有返回值
可以抛出异常
支持泛型的返回值
需要借助 FutureTask
类,比如获取返回结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class MyCallable implements Callable <Integer > { @Override public Integer call () throws Exception { int sum = 0 ; for (int i = 0 ; i < 100 ; i++) { sum += i; } return sum; } } class MyCallableTest { @Test void test () throws Exception { MyCallable myCallable = new MyCallable(); FutureTask<Integer> future = new FutureTask<>(myCallable); new Thread(future).start();; System.out.println(future.get()); } }
方法四:使用线程池(新)
提高响应速度(减少了创建新线程的时间)
降低资源消耗(重复利用线程池中线程,不需要每次创建)
便于线程管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class ThreadPool { public static void main (String[] args) { ExecutorService service = Executors.newFixedThreadPool(10 ); service.execute(new NumberThread1()); service.execute(new NumberThread2()); service.shutdown(); } } class NumberThread1 implements Runnable { @Override public void run () { for (int i = 0 ; i < 1000 ; i++) { if (i % 2 == 0 ) System.out.println(i); } } } class NumberThread2 implements Runnable { @Override public void run () { for (int i = 0 ; i < 1000 ; i++) { if (i % 2 != 0 ) System.out.println(i); } } }
3.3 线程的生命周期
3.4 线程的同步
方式一:同步代码块(多个线程需要同用一把锁lock)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class WindowRunnable implements Runnable { private int tickets = 100 ; @Override public void run () { System.out.println(Thread.currentThread().getName()); synchronized (this ){ while (tickets > 0 ) { System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + tickets); tickets--; } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class WindowRunnable implements Runnable { private int tickets = 100 ; @Override public void run () { System.out.println(Thread.currentThread().getName()); sell(); } private synchronized void sell () { while (tickets > 0 ) { System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + tickets); tickets--; } } } public class WindowThread extends Thread { private static int tickets = 100 ; @Override public void run () { sell(); } private static synchronized void sell () { while (tickets > 0 ) { System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + tickets); tickets--; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class WindowLock implements Runnable { private int tickets = 100 ; private Lock lock = new ReentrantLock(); @Override public void run () { lock.lock(); while (tickets > 0 ) { System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + tickets); tickets--; } lock.unlock(); } }
3.5 线程的通信 (1)两个线程交替从1打印到100
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Print implements Runnable { private Integer i = 1 ; @Override public void run () { synchronized (this ) { notify(); while (i <= 100 ) { System.out.println(Thread.currentThread().getName() + ": " + i++); } try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
(2)生产者消费者问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Productor implements Runnable { private Clerk clerk; public void setName (String name) { this .name = name; } private String name; public Productor (Clerk clerk) { this .clerk = clerk; } @Override public void run () { System.out.println(Thread.currentThread().getName() + ":" + name + "准备生产商品" ); while (true ){ clerk.produceProduct(); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Consumer implements Runnable { private Clerk clerk; public void setName (String name) { this .name = name; } private String name; public Consumer (Clerk clerk) { this .clerk = clerk; } @Override public void run () { System.out.println(Thread.currentThread().getName() + ":" + name + "准备消费商品" ); while (true ){ clerk.consumeProduct(); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class Clerk { private int productCount = 0 ; public synchronized void produceProduct () { if (productCount < 20 ) { System.out.println(Thread.currentThread().getName() + ":开始生产" + productCount + "个产品" ); productCount++; notify(); }else { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void consumeProduct () { if (productCount>0 ){ System.out.println(Thread.currentThread().getName() + ":开始消费" + productCount + "个产品" ); productCount--; notify(); }else { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class ProConTest { @Test void test () { Clerk clerk = new Clerk(); Productor productor = new Productor(clerk); productor.setName("生产者1" ); Consumer consumer = new Consumer(clerk); consumer.setName("消费者1" ); Thread p1 = new Thread(productor); Thread c1 = new Thread(consumer); Thread c2 = new Thread(consumer); p1.start(); c1.start(); c2.start(); try { p1.join(); c1.join(); c2.join(); } catch (InterruptedException e) { e.printStackTrace(); } } }
4. I/O流 4.1 File类的基本使用
1 2 3 4 5 6 7 File file = new File("hello.txt" ); File destFile = new File(file.getAbsoluteFile().getParent(), "good.txt" ); destFile.createNewFile(); destFile.delete();
4.2 IO流原理及流的分类 (1)流的分类
按数据单位:字节流(8bit)、字符流(16bit)
按数据流向:输入流、输出流
按流的角色:节点流、处理流
抽象基类
字节流
字符流
输入流
InputStream
Reader
输出流
OutputStream
Wrider
(2)流的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Test public void testFileReader () throws Exception { File file = new File("hello.txt" ); Reader reader = new FileReader(file); int data; while ((data = reader.read())!=-1 ){ System.out.print((char )data); } reader.close(); } @Test public void testFileReader1 () throws Exception { File file = new File("hello.txt" ); Reader reader = new FileReader(file); char [] cbuf = new char [5 ]; int len; while ((len = reader.read(cbuf)) != -1 ) { System.out.print(String.valueOf(cbuf, 0 , len)); } reader.close(); }
1 2 3 4 5 6 7 8 @Test void testFileWriter () throws Exception { File file = new File("out.txt" ); Writer w = new FileWriter(file); w.write("hello, world!你好" ); w.write("hello, world!你好" ); w.close(); }
4.3 节点流(文件流) 使用FileReader、FileWrite复制文本文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Test void testFileReaderWriterCopy () { File src = new File("hello.txt" ); File dest = new File("dest.txt" ); try { FileReader fr = new FileReader(src); FileWriter fw = new FileWriter(dest); char [] buf = new char [10 ]; int len = 0 ; while ((len = fr.read(buf)) != -1 ) { fw.write(buf, 0 , len); } fr.close(); fw.close(); } catch (Exception e) { e.printStackTrace(); } }
使用FileInputStream、FileOutputStream复制二进制文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Test void testFileInOutStreamCopy () { File src = new File("curl.jpeg" ); File dest = new File("curl1.jpeg" ); try { InputStream fin = new FileInputStream(src); OutputStream fout = new FileOutputStream(dest); byte [] buf = new byte [10 ]; int len = 0 ; while ((len = fin.read(buf)) != -1 ) { fout.write(buf, 0 , len); } fin.close(); fout.close(); } catch (Exception e) { e.printStackTrace(); } }
4.4 缓冲流 提升流的读取、写入速度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Test void testBufferedStream () { File src = new File("curl.jpeg" ); File dest = new File("curl1.jpeg" ); try { BufferedInputStream bin = new BufferedInputStream(new FileInputStream(src)); BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(dest)); byte [] buf = new byte [10 ]; int len = 0 ; while ((len = bin.read(buf)) != -1 ) { bout.write(buf, 0 , len); } bin.close(); bout.close(); } catch (Exception e) { e.printStackTrace(); } }
4.5 转换流 字节流和字符流之间的转换
1 2 3 4 5 InputStreamReader charIn = new InputStreamReader(new FileInputStream(src)); OutputStreamWriter charOut = new OutputStreamWriter(new FileOutputStream(dest));
4.6 标准输入、输出流 重定向标准输入、输出流
1 2 System.setIn(new FileInputStream(new File("hello.txt" ))); System.setOut(new PrintStream(new FileOutputStream(new File("out.txt" )), true ));
4.7 对象流 需要实现 Serializable
接口。
4.8 随机读写文件流
1 RandomAccessFile raf = new RandomAccessFile(new File("hello.txt" ), "r" );
5. 网络编程 5.1 IP
1 2 3 4 5 6 7 8 9 10 11 @Test void test () throws UnknownHostException { InetAddress inet1 = InetAddress.getByName("localhost" ); InetAddress inet2 = InetAddress.getByName("www.baidu.com" ); System.out.println(inet1); System.out.println(inet2); }
5.2 TCP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Test void client () throws Exception { Socket socket = new Socket(InetAddress.getByName("localhost" ), 9000 ); OutputStream os = socket.getOutputStream(); os.write("hello,计算机科学与技术" .getBytes(StandardCharsets.UTF_8)); os.close(); socket.close(); } @Test void server () throws Exception { ServerSocket ss = new ServerSocket(9000 ); Socket socket = ss.accept(); InputStream is = socket.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte [] buffer = new byte [5 ]; int len; while ((len = is.read(buffer))!=-1 ){ baos.write(buffer, 0 , len); } System.out.println(baos.toString()); is.close(); socket.close(); }
5.3 UDP 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Test void sender () throws Exception { DatagramSocket socket = new DatagramSocket(); String str = "UDP发送数据" ; byte [] data = str.getBytes(StandardCharsets.UTF_8); DatagramPacket packet = new DatagramPacket(data, 0 , data.length, InetAddress.getByName("localhost" ), 9000 ); socket.send(packet); socket.close(); } @Test void receiver () throws Exception { DatagramSocket socket = new DatagramSocket(9000 ); byte [] buffer = new byte [500 ]; DatagramPacket packet = new DatagramPacket(buffer, 0 , buffer.length); socket.receive(packet); System.out.println(new String(packet.getData(), 0 , packet.getLength())); }
6. 动态代理和反射
反射:允许程序在执行期间借助于Refelction API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
正常方式:引入“包类”名称 → 通过new实例化 → 取得实例对象
反射方式:实例化对象 → getClass()方法 → 得到完整的“包类”名称
6.1 获取Class实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test void test5 () throws Exception { Class clazz1 = Person.class; Class clazz2 = new Person().getClass(); Class clazz3 = Class.forName("indi.pancras.Person" ); ClassLoader classLoader = ReflectionTest.class.getClassLoader(); Class clazz4 = classLoader.loadClass("indi.pancras.Person" ); }
6.2 使用Class创建、访问对象
1 2 3 4 5 6 7 8 @Test void test2 () throws Exception { Class clazz = Person.class; Constructor cons = clazz.getConstructor(String.class, int .class); Person p = (Person) cons.newInstance("Tom" , 12 ); p.showName(); }
1 2 3 4 5 6 7 8 9 10 @Test void test3 () throws Exception { Class clazz = Person.class; Constructor cons = clazz.getConstructor(String.class, int .class); Person p = (Person) cons.newInstance("Tom" , 12 ); System.out.println(p.toString()); Field age = clazz.getDeclaredField("age" ); age.set(p, 10 ); System.out.println(p.toString()); }
1 2 3 4 5 6 7 8 @Test void test3 () throws Exception { Class clazz = Person.class; Constructor cons = clazz.getConstructor(String.class, int .class); Person p = (Person) cons.newInstance("Tom" , 12 ); Method showName = clazz.getDeclaredMethod("showName" ); showName.invoke(p); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void test4 () throws Exception { Class clazz = Person.class; Constructor cons = clazz.getDeclaredConstructor(String.class); cons.setAccessible(true ); Person p1 = (Person) cons.newInstance("Mike" ); System.out.println(p1); Field name = clazz.getDeclaredField("name" ); name.setAccessible(true ); name.set(p1, "Tom" ); System.out.println(p1); Method showAge = clazz.getDeclaredMethod("showAge" ); showAge.setAccessible(true ); showAge.invoke(p1); }
6.3 反射的应用:动态代理
1 2 3 4 5 public Object getInstance(String classPath) throws Exception{ Class clazz = Class.forName(classPath); return clazz.newInstance(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class ProxyClothFactory implements ClothFactory { private ClothFactory cloth; public ProxyClothFactory (ClothFactory cloth) { this .cloth = cloth; } @Override public void produceCloth () { System.out.println("一些准备工作" ); cloth.produceCloth(); System.out.println("一些收尾工作" ); } } class NikeClothFactory implements ClothFactory { @Override public void produceCloth () { System.out.println("生产Nike衣服" ); } } public class StaticProxyTest { public static void main (String[] args) { NikeClothFactory nike = new NikeClothFactory(); ProxyClothFactory proxy = new ProxyClothFactory(nike); proxy.produceCloth(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class NikeClothFactory implements ClothFactory { @Override public void produceCloth () { System.out.println("生产Nike衣服" ); } } class AntaClothFactory implements ClothFactory { @Override public void produceCloth () { System.out.println("生产Anta衣服" ); } } class ProxyFactory { public static Object getProxyInstance (Object obj) { return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new MyInvocationHandler(obj)); } } class MyInvocationHandler implements InvocationHandler { private Object obj; public MyInvocationHandler (Object obj) { this .obj = obj; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("一些准备工作" ); Object returnObj = method.invoke(obj); System.out.println("一些收尾工作" ); return returnObj; } } public class DynamicProxyTest { public static void main (String[] args) { ClothFactory proxy1 = (ClothFactory) ProxyFactory.getProxyInstance(new NikeClothFactory()); proxy1.produceCloth(); ClothFactory proxy2 = (ClothFactory) ProxyFactory.getProxyInstance(new AntaClothFactory()); proxy2.produceCloth(); } }