一、 JVM
- 核心运行流程、类的加载机制 Java文件->.class文件->类加载阶段(双亲委派,自下而上找上层的类加载器加载,再往下层找,直至找到)->类的生命周期(JVM)
- 内存结构 方法区(类信息、静态变量)、堆内存(类对象存储)
- GC 栈区、计数器不需要进行GC,与线程的生命周期同步; 方法区和堆内存需要进行GC; 可达性分析(GC ROOTS开始)来解决引用计数的相互调用问题; 标记-删除->标记->压缩->删除
- 调优 在做了架构和代码的调优后,才做JVM的调优; 一般是通过调整新生代、老年代、持久代的内存空间大小,以及选择合适的垃圾收集器(串行、并行;CMS)来进行逐步调优; 后续的话还可以考虑sql和操作系统的调优
二、语言的基本语法
- 基本结构(类是基本单元)
public class Hello { public static void main(String[] args) { System.out.println("Hello World!"); } }
- 流程控制
- 异常处理
public class Main { public static void main(String[] args) { try { proc1(); } catch (Exception e) { e.printStackTrace(); } } static void proc1() { try { proc2(); } catch (NullPointException e) { throw new IllegalArgumentException(e); // e 原始的异常信息 } } static void proc2() { throw new NullPointException(); } }
- 反射。通过字符串直接创建类对象,并访问其成员变量或者方法,常用于框架代码的实现,避免出现大量的条件判断
public class Main { public static void main(String[] args) throws Exception { // 获取Person的hello方法 Method h = Person.class.getMethod("hello"); // 对Student实例调用hello方法 h.invoke(new Student()); } } class Person { public void hello() { System.out.println("Person:hello"); } } class Student extends Person { public void hello() { System.out.println("Student:hello"); } }
- 泛型。 代码复用,减少重复的逻辑代码; 类型参数化,在编译期间做类型检查
// 泛型类、泛型方法 class DataHolder<T>{ T item; public void setData(T t) { this.item=t; } public T getData() { return this.item; } // 泛型方法 public <E> void PrinterInfo(E e) { System.out.println(e); } } // 通配符 List<? extends Fruit> flist = new List<Apple>(); // 泛型擦除 //虚拟机不知道泛型,都是按Object处理 //编译器把泛型T当做Object处理,需要转型时,根据T的类型,自动进行安全的类型转换
- 多线程
// 1. 基本使用 public class Main { public static void main(String[] args) throws InterruptedException { Thread t = new MyThread(); t.start(); //这里不能直接调用run, 不会启动新的线程 Thread.sleep(1); // 暂停1毫秒 t.interrupt(); // 中断t线程 t.join(); // 等待t线程结束 System.out.println("end"); } } class MyThread extends Thread { public void run() { int n = 0; while (! isInterrupted()) { n ++; System.out.println(n + " hello!"); } } } // 2. 线程池 // 常用的三种使用方式: Executors.newCachedThreadPool():无限线程池 Executors.newFixedThreadPool(nThreads):创建固定大小的线程池 Executors.newSingleThreadExecutor():创建单个线程的线程池 // 均是基于ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) .. public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
三、 面向对象编程
3.1. 继承与多态
//多态: 对某个类型的方法的调用,要在执行时才知道是对哪个类型的方法的调用
class Income {
protected double income;
public double getTax() {
return income * 0.1; // 税率10%
}
}
class Salary extends Income {
@Override // 方法名和返回值都相同
public double getTax() {
if (income <= 5000) {
return 0;
}
return (income - 5000) * 0.2;
}
}
class StateCouncilSpecialAllowance extends Income {
@Override
public double getTax() {
return 0;
}
}
public double totalTax(Income... incomes) {
double total = 0;
for (Income income: incomes) {
total = total + income.getTax(); //并不需要关心具体是哪一项的收入
}
return total;
}
3.2. 抽象类与接口
// 接口和抽象类类似, 可以只定义方法,没有实现。
但是接口更彻底,变量都没有。
一个类可以实现多个接口,接口间可以继承接口
interface Hello {
void hello();
}
// 接口继承接口
interface Person extends Hello {
void run();
String getName();
}
// 类实现接口
class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(this.name + " run");
}
@Override
public String getName() {
return this.name;
}
@Override
public void hello() {
System.out.println("Hello World!");
}
}
3.3. 包与模块
//1. 包的作用:避免类名的冲突
// Person.java
package ming;
// 导入mr.jun包的所有class:
import mr.jun.*;
public class Person {
public void run() {
Arrays arrays = new Arrays();
}
}
//2. 模块的作用:声明模块间的依赖; 封装隔离,模块的可读性(requires、exports), 类型的可访问性(public, protect, private)
module com.foo.bar {
requires org.baz.qux; // 包含
exports com.foo.bar.alpha; // export给其它模块
exports com.foo.bar.beta;
}
四、Spring & J2EE
- Servlet:web服务器的底层封装
- IoC容器:组件的创建、基于依赖组装组件、依次销毁组件的解决方案 (中间件/商)
五、I/O & 网络
5.1 单线程
//一个while循环,一个个请求处理,返回后处理下个请求
// 100ms处理一个请求, 1s只能处理10个请求
ServerSocket listener = new ServerSocket(8080);
try {
while (true) { // 循环处理链接,和响应请求
Socket socket = listener.accept();
try {
handleReq(socket);
} catch(IOException) {
e.printStackTrace();
}
}
} finally {
listener.close();
}
public static void handleReq(Socket socket) throws IOException {
try {
//socket.getInputStream
//socket.getOutputStream out.write("xxxx")
} finally {
socket.close();
}
}
5.2 多线程
//单线程模式下,如果请求处理阻塞在了IO, 那么无法充分利用cpu。利用多线程,可以同时并发处理多个请求
public static class HandleReq extend Tread {
final Socket socket;
public HandleReq(Socket socket) {
this.socket = socket;
}
public void run() {
handleReq(socket)
}
}
while(true) {
Socket socket = listener.accept();
new HandleReq(socket).start();
}
5.3 线程池
//多线程频繁的创建和销毁, 是对系统资源的巨大浪费。
//线程池预先创建一批线程,进行复用
// 设计: 线程数有baseNum 和 maxNum, 当ThreadNum>baseNum且<maxNum的时候, 有新的请求需要处理,则创建新的线程进行处理;
// 当空闲时间大于KeepAliveTime的时候, 删除大于base Num的线程;
// 当线程已经占用满了,还有新的请求的话, 可以加入队列等待, 等队列满了, 再直接拒绝; 也可以直接拒绝, 看场景
ExecutorService executor = Executors.newFixedTreadPool(4);
...
while(true) {
Socket socket = listener.accept();
executor.submit(new HandleReq(socket));
}
...
六、简单实践–hello world的web工程
- Nginx+Tomcat(servlet)+java
- yum install 安装jdk
- javac 编译成.class文件
- java HelloWorld 运行