2 语言基础 2

Java 技术体系

Java 核心本质在于 MVC 设计模式
JSP、Servlet 是技术的实现本质

本质技术:
JSP、HTML、CSS、JavaScript

前端 UI 设计 (HTML、CSS)

前端工程师 ( js 动态效果)

WEB 工程师(JSP、PHP、Node.JS)

控制层 前端 web 开发

业务层 只考虑操作本质

第一阶段 基础阶段

  1. SQL 语句:查询、更新、建表、约束
  2. Java 基础:基础语法、面向对象、类库、类集、IO、JDBC、DAO、设计模式
  3. JSP 开发:JSP、DAO、MVC(EL、JSTL)

总结:单表 CURD + 分页 + 上传

重复代码设计

观察问题的两个点:时间复杂度、空间复杂度

第二阶段 中级开发阶段

主要针对代码设计进行完善

  1. 性能:AJAX
  2. XML 与 DOM 解析、JSON
  3. jQuery、Jsonp
  4. GIT、SVN、Maven

第三阶段 框架开发

控制层、业务层、数据层改善

  1. Struts2:控制器、拦截器、实现原理
  2. Hibernate: 解决数据层开发设计,单表 CURD、一对多、多对多。缓存,设计思想、缺陷
  3. Spring IOC 与 AOP, SHH 整合
  4. MyBatis 好处,与 Hibernate 区别
  5. SpringMVC 与 Struts2 实现区别
  6. SpringMVC + MyBatis 开发与整合

多线程工具类

多线程同步处理

synchronized

JDK>=1.5 引入了
java.util.concurrent

package demo;

import java.util.concurrent.locks.ReentrantLock;

class MyTask {
    private static final ReentrantLock lock = new ReentrantLock();
    private static int count = 0;

    public void doing() {
        lock.lock();

        count ++;

        try{
            System.out.println(Thread.currentThread().getName() + " " + count);
        }finally {
            lock.unlock();
        }
    }
}

public class LockDemo {
    public static void main(String[] args) {
        for(int i=0; i<10; i++){
            new Thread(()->{
                new MyTask().doing();
            }).start();
        }
    }
}

输出结果

Thread-0 1
Thread-9 2
Thread-3 3
Thread-2 4
Thread-5 5
Thread-7 6
Thread-4 7
Thread-6 8
Thread-8 9
Thread-1 10

反射参数

class

getClass()

反射与 new 的关系

package demo;

interface IMessage{
    void print();
}

class MyMessage implements IMessage{
    @Override
    public void print() {
        System.out.println("MyMessage");
    }
}

public class reflectDemo {
    public static void main(String[] args) throws Exception {
        // 相当于 IMessage message = new MyMessage();
        Class<?> clazz = Class.forName("demo.MyMessage");
        IMessage message = (IMessage)clazz.newInstance();

        clazz.getMethod("print").invoke(message);
    }
}

方法变量与同步

方法中的变量是局部作用域,同步只考虑类属性

1、synchronized 同步方法

package demo;

class MyThread implements Runnable {
    private int count = 5;

    @Override
    public synchronized void run() {
        System.out.println(Thread.currentThread().getName() + " " + this.count--);
    }
}

public class SyncDemo {
    public static void main(String[] args) {
        MyThread t = new MyThread();

        for (int i = 0; i < 5; i++) {
            new Thread(t).start();
        }
    }
}

输出结果

Thread-0 5
Thread-2 4
Thread-1 3
Thread-4 2
Thread-3 1

2、不同步

package demo;

class MyThread implements Runnable {
    private int count = 5;

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " " + this.count--);
    }
}

public class SyncDemo {
    public static void main(String[] args) {
        MyThread t = new MyThread();

        for (int i = 0; i < 5; i++) {
            new Thread(t).start();
        }
    }
}

输出结果

Thread-0 5
Thread-3 2
Thread-2 3
Thread-1 4
Thread-4 1

高并发包

java.util.concurrent

四种线程池

  1. 任意扩展的线程池
  2. 定长线程池
  3. 线程调度池
  4. 单线程池

接口特点:

不同子类对同一方法有不同的实现

  1. Hashtable 线程安全,一个时刻只允许一个线程访问
  2. HashMap 所有方法都是异步处理,非线程安全,访问速度快
  3. ConcurrentHashMap 可并发、高速访问

进程间通讯

进程间通讯:不同进程之间的 JVM 通讯

可以使用公共文件,或者直接进行管道流处理

进程和线程

进程执行速度慢
线程执行速度快

线程收到进程控制

集合信息

List 优先使用 get() 方法获取元素

接口标准

标准指的是所有类都要奉行的法则

接口的使用

  1. 接口:核心意义是暴露远程结构(方法视图)
  2. 抽象类:给接口和子类之间做过过渡使用

链表

内部类特点:
内部类可以方便的与外部类之间进行私有属性声明
内部类如果使用了 priate 声明,那么外部将无法直接使用它

外部类形式

class Link{}
class Node{}

内部类形式

class Link{
    private class Node{}
}

线程池

无限大小的线程池

package demo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo {
    public static void main(String[] args) {
        // 创建一个无限大小的线程池
        ExecutorService service = Executors.newCachedThreadPool();

        for (int i = 0; i < 10; i++) {
            final int temp = i;
            service.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " " + temp);
                }
            });
        }
    }
}

固定个大小的线程池

package demo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo {
    public static void main(String[] args) {
        // 创建一个3个大小的线程池
        ExecutorService service = Executors.newFixedThreadPool(3);

        for (int i = 0; i < 10; i++) {
            final int temp = i;
            service.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " " + temp);
                }
            });
        }
    }
}

取得可用线程池大小

Runtime.getRuntime().availableProcessors()

线程同步工具类

CountDownLatch 等待所有人都走了,我再干;一计到底,不可以重置
CyclicBarrier 汇聚多个等待线程,都到了,一起干,可以重置

不使用等待线程

package demo;

public class ThreadPoolDemo {
    public static void main(String[] args) {

        for (int i = 0; i < 3; i++) {
            final int temp = i;
            new Thread(() ->
            {
                System.out.println(Thread.currentThread().getName() + " " + temp);
            }
            ).start();
        }

        System.out.println("主线程执行");
    }
}

执行结果

主线程执行
Thread-2 2
Thread-0 0
Thread-1 1

使用 CountDownLatch

package demo;

import java.util.concurrent.CountDownLatch;

public class ThreadPoolDemo {
    public static void main(String[] args) throws InterruptedException {
        // 3个线程执行完后再继续
        CountDownLatch countDownLatch = new CountDownLatch(3);

        for (int i = 0; i < 3; i++) {
            final int temp = i;
            new Thread(() ->
            {
                System.out.println(Thread.currentThread().getName() + " " + temp);
                // 执行完成1次
                countDownLatch.countDown();
            }
            ).start();
        }

        // 阻塞主线程执行
        countDownLatch.await();
        System.out.println("主线程执行");
    }
}

执行结果

Thread-0 0
Thread-2 2
Thread-1 1
主线程执行

使用 CyclicBarrier

package demo;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class ThreadPoolDemo {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(2);

        for (int i = 0; i < 3; i++) {

            new Thread(() ->
            {

                System.out.println(Thread.currentThread().getName() + "[before]");

                try {
                    cyclicBarrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + "[after]");
            }
            ).start();
        }
    }
}

执行结果

Thread-0[before]
Thread-2[before]
Thread-1[before]
Thread-2[after]
Thread-0[after]
(线程卡主了)

基本类型与包装类型

JDK1.5 之后提供了自动装箱拆箱处理机制

  1. 包装类以对象的形式运行
  2. 包装类可以进行 null 的描述
  3. 基本数据类型型默认值是对应默认值,包装类默认值是 null
  4. 对象内容类 ov 都会使用包装类,便于 null 的控制

基本类型与引用传递

Java 中两种数据类型:

  1. 引用类型: 可以发生引用传递
  2. 基本类型: 只是一个值拷贝

包装类提供了 null

Mybatis 等使用包装类替代基本数据类型

使用 Object 作为接收参数

使用泛型来避免向下转型的操作

尽量减少 Object 使用

转型

向下转型:(不推荐)可以达到参数的统一,需要强制处理,造成类型不匹配
向上转型:最顶端是 Object

package demo;

public class StringTest {
    public static void main(String[] args) {
        String str = "Hello";

        // 向上转型
        Object obj = str;

        // 向下转型
        String ref = (String) obj;
    }
}

引用传递

引用传递本质:

同一块堆内存能够被不同的栈内存指向

引用数据类型真正的内容在堆内存中

基本数据类型是数值传递

JSP 中 JSTL 和 EL 操作,帮助用户回避掉转型操作

package demo;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

class Student{
    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class StringTest {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // 向上转型
        Object obj = new Student("Tom");

        Class<?> clazz = obj.getClass();
        Method method = clazz.getMethod("getName");
        System.out.println(method.invoke(obj));
    // Tom

    }
}

泛型通配符

package demo;

interface IMessage{
    void print();
}

class TextMessage implements IMessage{
    @Override
    public void print() {
        System.out.println("TextMessage");
    }
}

class Factory{
    public static <T> T getInstance(Class<T> clazz) throws IllegalAccessException, InstantiationException {
        return clazz.newInstance();
    }
}

public class FactoryDemo {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        IMessage message = Factory.getInstance(TextMessage.class);
        message.print();
    }
}

泛型中的“T”与“?”的区别?

<T> 用于泛型类声明
<?> 用于方法接收参数,或者返回类型 只能取得内容,不能设置内容

虚拟内存

操作系统会将硬盘进行内存虚拟化
相当于硬盘可以模拟内存

Java8 开始取消了永久代,使用元空间来进行操作

面试题

代码块(常用语 junit)

  1. 普通代码块
  2. 构造代码块 优先于构造方法
  3. static 代码块 优先于构造方法,优先于主方法
  4. 同步代码块

子类实例化一定会默认执行父类构造方法,再执行子类自己的构造方法

程序执行是由父到子的顺序执行

package demo;

class A {
    static {
        System.out.println("1");
    }

    public A() {
        System.out.println("2");
    }
}

class B extends A {
    static {
        System.out.println("3");
    }

    public B() {
        System.out.println("4");
    }
}


public class StringTest {
    public static void main(String[] args) {
        A a = new B();
        a = new B();
    }
}

执行结果

A a = new B();
1 -> static { System.out.println("1"); }
3 -> static { System.out.println("3"); }
2 -> public A() { System.out.println("2"); }
4 -> public B() { System.out.println("4"); }

a = new B();
2 -> public A() { System.out.println("2"); }
4 -> public B() { System.out.println("4"); }

转义字符处理

\\ \n \t

正则中写法

\\d

资源注入

@Resource、@Autowired 两个注解都是直接利用反射进行对象的引用设置

IO

异步 IO 等待返回后继续
同步 IO 不等待返回,直接继续

BIO Blocking 同步阻塞 IO 传统模式
NIO Non-blocking 同步非阻塞 IO 零拷贝
AIO Asynchronous 异步非阻塞 IO

字节流与字符流

所有磁盘保存的文件和网络传输的文件实际上都是字节数据
为了处理中文更方便,使用字符流来操作

内存流和管道流

内存流:需要产生 IO 的情况下,但是又不希望产生实际的存储文件所采用的一种 IO 方案

管道流:来自 Unix 系统中的概念,指的是两个进程之间的通讯关系,同一个程序由于运行的进程不同,所以其拥有各自的数据存储空间

Java 并没有进程的开发,是多线程编程语言
Python 提供多进行程开发,还有协程开发

Java 在多线程的结构上使用了管道的概念

缓存流与内存流

内存流: 将所有数据在内存之中进行完整的处理操作

缓存流:暂时的操作, Scanner