Java 基础

类:一类抽象的事务,还不具体。

  • eg:人,是一个抽象的概念,是不是没有具体的表达,这个“人”指的是谁。
  • 人拥有一些公共属性,age 、sex 、height ,和方法 eat() 、go() ;组成了一个类 Person
public class Person {
    
    //人都有属性、方法
    
    /**
     * 年龄
     */
    private int age;
    /**
     * 重量
     */
    private Double height;
    /**
     * 性别
     */
    private char sex;
    
    public void go(){
        System.out.println("跑");
    }
    
    public void eat(){
        System.out.println("吃");
    }
}

对象:具体的事务

  • eg:Person xiaohua = new Person(); Person xiaoming= new Person();
  • new 创建对象,就具体到了某个存在的事务,小花、小红

面向对象:

  • 面向一个个对象,用对象来处理问题,是一种思维方式,来思考问题
  • eg:小明要吃棒棒糖,用面向对象的思维来处理:
  • 小明 → 人 ,抽象出 人 Person 这个类
  • 棒棒糖 → 零食,抽象出 零食 Snacks这个类
  • 吃 → 代表动作,小明去吃,说明 人这个类有个 方法是吃
       Person xiaoming = new Person("小明")
       Snacks bbt= new Snacks("棒棒糖")
       xiaoming.eat(bbt); //小明在吃棒棒糖

       Person xiaohua = new Person("小花")
       Snacks qkl= new Snacks("巧克力")
       xiaohua .eat(bbt); //小花在吃巧克力

简单来说呢,面向对象的思维,编写代码更灵活,容易扩展;
相对于面向过程,没有那么死板,维护或修改功能时,那么蛋疼;

封装:

  • 把私有实现细节隐藏起来,对外只暴露调用的方法,而他们不用关心怎么实现的
  • 类似 “黑盒”,封装细节,如:给一个输入,返给你输出,而不用关心,内部复杂或简单的实现
  • eg: 类也是一个简单的 “封装” ,私有的属性数据,暴露出获取设置数据的 get/set 方法
    //比如设置年龄,不用关心,具体有什么逻辑,对外只需要知道设置一个了值
    public void setAge(int age) {
        if (age>18){
            this.age = 18;
            System.out.println("我一直都是18岁");
        }else {
            this.age = age;
        }
    }
    public int getAge() {
    	if(this.age<18){
    	    this.age=18;
		}
        return age;
    }

继承:

  • extends 继承类 ,继承机制
  • 子类继承父类,就可以自动拥有父类 非私有的、非静态的、所有内容
  • eg:兔子 extends 草食动物,就可以拥有草食动物共有的一些属性,如:吃草,是兔子这个类,就不用声明吃草了。
  • 简化代码开发,抽取公共的代码,比如写一些基础类,包含都有的一些操作,而子类也可以拥有自己特有的一些属性特点
  • java 类 只能单继承

多态:简单说就是 多种形态,动态编译,扩展性强

  • eg: 引用指向的多态
  • eg: 方法的多态
  • eg: 接口的多态
//同样的person指向了 personA、personB
//同样的 go() 跑方法,重写后可以有不同的实现
//同样的 moveBrick() 搬砖,可以写代码,也可以卖保险
//是不是多样化
public class PersonA extends Person implements Work {
    @Override
    public void go() {
        System.out.println("飞快的跑");
    }

    @Override
    public void moveBrick() {
        System.out.println("写代码");
    }
}

public class PersonB extends Person implements Work{
    @Override
    public void go() {
        System.out.println("慢慢的跑");
    }

    @Override
    public void moveBrick() {
        System.out.println("销售保险");
    }
}

public class Test {

    public static void main(String[] args) {
        Person a = new PersonA();
        Person b = new PersonB();
        a.go(); //飞快的跑
        b.go(); //慢慢的跑

        Work wa =new PersonA();
        Work wb =new PersonB();
        wa.moveBrick(); //写代码
        wb.moveBrick(); //销售保险
    }
}

抽象:就是不具体的东西,在java里,只声明,不实现

抽象类:抽象的类,abstract 修饰的类,不能被实例化(不能new)、有构造器(初始化值)

  • 抽象出公有的方法约束(抽象方法),让子类来实现,简化代码
  • 也拥有平常类的普通属性,方法等

接口:interface 修饰,就是定义功能,规范,定义一组规则,实现约束和实现分离;

  • 是种特殊的抽象类,相对于抽象类,更抽象、更专业,就是为了定义抽象方法,定义功能,让别人实现,实现约束和实现分离
  • 接口可以多继承接口public interface IA extends IB,IC
  • 可以多实现 implements 接口public class A extends AbstractA implements IA,IB,IC
    1

类加载过程:

  • 加载:将 .java文件编译成 class字节码文件,将字节码内容加载到内存中
    – (将类的信息,静态变量、方法、常量池、代码等…加载到方法区,生成运行时数据结构)
    – (在中生成该类的Class对象,代表类的所有信息)
    – (在中 – new A(); 这个对象A 就会指向生成的Class对象,从而获取所有数据)
  • 验证,确保将加载的类信息符合当前jvm规范
    准备:为类变量(静态块、变量)赋初始值
    解析:将虚拟机中符合引用替换成直接引用
  • 初始化
    –执行 jvm的类构造器 <clinit>() 方法,合并静态代码块赋值动作,并检查父类是否初始化,并且jvm会保证一个类的 <clinit>() 方法在多线程环境中被正确加锁和同步。
<clinit>()int a=10;
     static m=100;
     static{
     	...
     }

双亲委派机制:

  • 一种安全机制,如,定义一个java.lang.String ,在加载器,加载这个类是,会先找系统类加载器有没有这个包,然后往上找,扩展类加载器、根加载器,如果有,就会用本来就有的包,不用加载现在的。

反射:

  • 程序在运行期间,通过反射API(java.lang.Class)获取类的任何内部信息,并且可以操作
  • 通过Class对象来反向 → 获取类的信息 ,因为该类的Class对象就包含了所有该类信息
  • 反射操作会对 性能有影响
		Class<Person> c1 = Person.class;
        //类名
        c1.getSimpleName();
        //方法
        Method setAge = c1.getMethod("setAge", int.class);
        //属性
        c1.getDeclaredFields();
        //构造器
        c1.getConstructors();
        //获取注解
        c1.getAnnotation(MyAnnoation.class);
        //创建对象
        Person person = c1.newInstance();
        //执行方法
        setAge.invoke(person,10);

注解:

  • 对程序做出解释,可以被其它程序读取,也起到检查和约束的作用
  • 元注解meta-annoation:负责解释其它注解 的注解
    @Target 注解目标,用在哪些地方
    @Retention 作用阶段 source 源代码、class 编码、runtime 运行时,runtime时,前两个都有效
    @Decumented 是否生成在javadoc中
    @Inherited 表示子类是否可以继承该注解
// MyAnnoation 注解名,String name() 注解参数 ..  
@Inherited
@Documented
// TYPE 类上、FIELD 属性上 、METHOD 方法上 、PARAMETER 参数上 、 CONSTRUCTOR 构造器上...
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_USE,TYPE_PARAMETER})
// 运行时有效
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyAnnoation {
    //定义注解参数
    String name();

    String value() default "";

    String[] ways() default {"搬砖","打酱油"};

    // -1 代表不存在
    int age() default -1;

}

泛型:

  • 一种参数化的数据类型,用一个标识符来声明一个参数eg:T、N、E,不明确具体的类型,在调用的时候确认,在编译的时候具体替换。
//类
public class Person<T> {

    private T t;
    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}
//声明的时候确定
Person<Integer> person = new Person<>();
person.setT(1);
System.out.println(person.getT());   

//接口
public interface ID<T> {
    T aa();
} 
public class D implements ID<String> {
    @Override
    public String aa() {
        return "";
    }
}

//方法
public <T> void test(T t, List<T> list){
    
}

进程:

  • 运行起来的一个程序

线程:

  • 一个进程要运行起来就需要运行至少一个线程,类似一个程序的功能
  • 一个独立的执行路径,是CPU调度和执行的单位
  • 线程的运行是有CPU调度的
  • 线程之间有 资源抢夺问题
  • 线程会带来额外的开销
  • 每个线程在自己的工作内存交互

线程创建:

public class ThreadA extends Thread {
    /**
     * Thread 本身实现了 Runnable接口
     * 线程入口
     */
    @Override
    public void run() {
        //线程体
        System.out.println("线程A。。。");
    }

    public static void main(String[] args) {
        ThreadA t1 = new ThreadA();
        ThreadA t2 = new ThreadA();
        //就绪,不是立即执行,等待CPU调度
        //main, t1,t2 是并发执行的
        t1.start();
        t2.start();
    }
}
public class ThreadB implements Runnable {

    /**
     * 推荐使用Runnable,避免单继承的局限性
     */
    @Override
    public void run() {
        System.out.println("线程b");
    }

    public static void main(String[] args) {
        //通过线程对象,来开启线程
        Thread t1 = new Thread(new ThreadB(),"线程一");
        Thread t2 = new Thread(new ThreadB(),"线程二");
        t1.start();
        t2.start();
    }

}
public class ThreadC implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println("执行Callable线程");
        return "哈哈";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ThreadC t1 = new ThreadC();
        ThreadC t2 = new ThreadC();
        ExecutorService executorService = newFixedThreadPool(2);
        Future<String> s1 = executorService.submit(t1);
        Future<String> s2 = executorService.submit(t2);
        System.out.println(s1.get());
        System.out.println(s2.get());
        executorService.shutdownNow();
        //--- get() 可能会阻塞、执行会有缓存
        FutureTask futureTask = new FutureTask(new ThreadC());
        new Thread(futureTask).start();
        Object o = futureTask.get();
    }
}

Thread → 静态代理

/**
 * @Description
 * @Author 静态代码模式
 * @Date 2021/2/20
 * @modify
 */
public class StaticProxy {

    public static void main(String[] args) {
        //婚庆帮助你结婚,代理 → you
        Wedding wedding = new Wedding(new You());
        wedding.toMarry();
        //线程, Thread 代理 →实现了Runnable的对象
        new Thread(()-> System.out.println("结婚")).start();
    }

}

/**
 * 公共接口,代理,真实,都要去做的事情
 */
interface Marry{
    /**
     * 结婚
     */
    void toMarry();
}

/**
 * 你
 */
class You implements Marry{
    @Override
    public void toMarry() {
        System.out.println("小树要结婚了");
    }
}

/**
 * 婚庆
 */
class Wedding implements Marry{
    private Marry target;

    public Wedding(Marry target) {
        this.target = target;
    }

    @Override
    public void toMarry() {
        before();
        this.target.toMarry();
        after();
    }

    private void after() {
        System.out.println("结婚之后收尾款");
    }

    private void before() {
        System.out.println("结婚之前布置现场");
    }
}

线程状态:

  • 创建( NEW ):new Thread()
  • 就绪:new Thread().start() ,等待CPU调度
  • 运行( RUNNABLE ):正在运行,执行run()方法了
  • 阻塞( BLOCKEDWAITINGTIMED_WAITING):如 Thread.sleep(200)TimeUnit.DAYS.sleep(1)
  • 死亡( TERMINATED):线程运行停止

常见方法:

		//设置优先级,1的权重最高,
        t1.setPriority(1);
        //线程休眠,指定时间后自动恢复,模拟网络延迟,测试线程安全
        //同时 sleep() 不会释放锁
        Thread.sleep(200);
        //线程插队,强制执行,等待该线程执行完成后,再执行其它线程,其它线程阻塞
        t1.join();
        //暂停线程,不阻塞回到就绪状态,等待CPU调度,重新竞争
        Thread.yield();
        // 是否存活
        boolean alive = t1.isAlive();
        //终止线程,不建议使用
        //使用自定义标志位来停止,让线程自己停止
        t1.interrupt();t1.stop();
        //设置守护线程
        t1.setDaemon(true);
        //唤醒一个处于等待线程
        t1.notify();
        //唤醒同一个对象上,所有等待的线程,优先唤醒优先级高的线程
        t1.notifyAll();

线程停止:

public class TestStop implements Runnable {

    private boolean flag=true;

    @Override
    public void run() {
        while (flag){
            System.out.println("TestStop线程...");
        }
    }

    public void stop(){
        flag=false;
    }

    public static void main(String[] args) {
        TestStop testStop = new TestStop();
        Thread(testStop).start();
        for (int i = 0; i < 100; i++) {
            if (i==90){
            	//停止线程
                testStop.stop();
            }
        }
    }

}

并行:当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)

并发:当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状

线程同步:

  • 并发:多个线程访问同一个对象
  • 同步:当多个对象要修改对象数据时,就需要同步,是一种等待机制,让线程等待前一个线程执行完成,后再下一个线程执行。(进入这个对象的等待池,线程队列)
  • 每个线程都是自己的工作内存
  • 线程安全: 队列+锁
  • synchronized :每个对象本身就拥有一把锁 ,让线程获取资源排队
  • JUC、java.util.concurrent java并发包
    –常见类:ConcurrentHashMapCopyOnWriteArrayList、…
  • 死锁:同一资源被多个线程使用,两个或多个线程都在等待对方释放资源,造成僵持卡死
    jstack pid 检查死锁

悲观锁:假设最坏的情况,认为会出现线程安全的问题,直接加锁 👇

隐式锁:默认操作对象是 this,应该锁的对象是,被修改数据的对象,出了作用域自动释放
synchronized(targetObj.class){}
synchronized void meathodA(){} //锁,调用方法的对象

显示加锁:
ReentrantLock 可重入锁,实现了Lock,拥有与 synchronized 相同的并发性和内存语义,锁的是块儿,手动加锁、释放锁

			private final Lock lock = new ReentrantLock();//默认非公平锁,可以插队获取锁
			Condition condition1 = lock.newCondition(); //精准等待、唤醒
            Condition condition2 = lock.newCondition();
            condition1.await(); // wait()
            condition2.signal(); // notify()
 			lock.lock();//加锁
            try {
                //加锁内容
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();//释放锁
            }
            
 可重入锁: 获取外层锁之后,自动获取内部锁
 -------
public class SayTest {

    public static void main(String[] args) {
        //如果不可重入,因为锁的对象都是Say,线程A say1()方法执行完后,释放锁,执行线程B的say1()
        /**
        *线程Asay1
		线程Asay2
		线程Bsay1
		线程Bsay2
        */
        Say say = new Say();
        new Thread(()->{say.say1();},"线程A").start();
        new Thread(()->{say.say1();},"线程B").start();

    }
 
}
class Say{

    public synchronized void say1(){
        System.out.println(Thread.currentThread().getName()+"say1");
        say2();
    }

    public synchronized void say2(){
        System.out.println(Thread.currentThread().getName()+"say2");
    }

}

乐观锁:假设可能不会出现线程安全的问题,不直接上锁

  • CAS机制 Compare-And-Swap(比较并交换),非阻塞同步
    旧的预期值A,新值B,当A=B时认为是线程安全的,如果!= 代表有其它线程修改了,一直循环下去直到预期与更新相等后,返回最新的值。
  • 如:java.util.concurrent.atomic 包下得类,AtomicInteger 等原子类,unsafe.compareAndSwapInt(this, valueOffset, expect, update)
    while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4))
  • 数据库的 version 版本标志 where id=#{id} and version=#{version} ,更新一次version +1,预期的version应该相等
  • 原子引用类 AtomicStampedReference
  • 同时处理ABA问题,A线程修改过主内存中值,而B线程却毫无察觉
 		AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<>(1, 1);
        //当前版本号 时间戳
        int curStamp = stampedReference.getStamp();
        boolean b = stampedReference.compareAndSet(1, 2, curStamp, curStamp + 1);
AtomicInteger atomicInteger = new AtomicInteger(1);
atomicInteger.compareAndSet(1,2);//如果当前的值是1,则更新值为2

// 源代码中.. expect 期望值, update 更新的值
public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

//源代码中.. Unsafe类: c++可以操作内存,java通过本地方法 native 调用c++操作内存
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;  //对象地址偏移值
    static {
        try {
            valueOffset = unsafe.objectFieldOffset 
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    
    private volatile int value;
    // +1
	public final int getAndIncrement() {
	    return unsafe.getAndAddInt(this, valueOffset, 1);
	}
	//unsafe.getAndAddInt(this, valueOffset, 1);
    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            //public native int getIntVolatile(Object var1, long var2);
            //var5对象内存地址中的值= 当前对象 + 对象偏移值
            var5 = this.getIntVolatile(var1, var2);
            // var1 当前对象 var2 对象偏移值 var5 对象地址 var5 + var4 对象地址+1
            // 如果 当前对象和对象偏移值计算出的对象内存地址中的值,与预期的相等,则执行+1
            // 内存操作效率很高
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
		//自旋锁 👆 ,阻塞不停循环直到达到期望值
        return var5;
    }

线程池:

  • 提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中
    可以避免频繁创建销毁、实现重复利用。
  • corePoolSize : 核心线程数,正常情况工作的线程数量
    – CPU密集型 Runtime.getRuntime().availableProcessors(),CPU核数设置线程数
    – IO密集型 程序中十分消耗IO资源的数量线程,再加上部分线程
  • maximumPoolSize: 最大线程数 (池最多有多少线程),阻塞队列容量 + 核心线程数
  • keepAliveTime: 阻塞队列中等待线程的,最长等待时间,超过就不等了
  • ExecutorService 线程池接口 、 Executors 线程工具类,线程工厂
  • BlockingQueue<Runnable> workQueue 阻塞队列,等候线程队列
  • RejectedExecutionHandler handler 拒绝策略,当 阻塞队列和工作队列都满了,新来的线程的处理策略
    new ThreadPoolExecutor.AbortPolicy() 不处理并且抛出异常
    new ThreadPoolExecutor.CallerRunsPolicy() 由调用线程处理该任务 【谁调用,谁处理】
    new ThreadPoolExecutor.DiscardPolicy() 抛弃,不抛出异常
    new ThreadPoolExecutor.DiscardOldestPolicy() 丢弃线称队列的旧的任务,将新的任务添加
           ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

ExecutorService executorService = 
                 new ThreadPoolExecutor(5, 10, 20,TimeUnit.SECONDS,
                 new LinkedBlockingQueue<>(5),new CustomizableThreadFactory("创建线程名称-"),
                 new ThreadPoolExecutor.AbortPolicy());
        executorService.execute(new MyThread());
        executorService.shutdown();                              

Lamda表达式:

  • 函数式接口:任何接口如果只包含唯一一个抽象方法,那么它就是一个函数式接口,就可以通过lamda来创建接口对象
public class TestLambda {

    public static void main(String[] args) {
        //匿名内部类,必须借助接口或者父类
        ITest test = new ITest() {
            @Override
            public void say(String content) {
                System.out.println("哈哈哈");
            }
        };
        //Jdk8以后,简化写法
        ITest test2= (String content) ->{
            System.out.println("哈哈哈"+content);
        };
        //简化,单行时
        ITest test3= content -> System.out.println("哈哈哈"+content);
        test3.say("111");
    }

}

class Test implements ITest{
    @Override
    public void say(String content) {
        System.out.println("..."+content);
    }
}

/**
 * 函数式接口
 */
interface ITest{
    void say(String content);
}

4个常用型函数式接口 (常用方法参数):

//输入, 输出什么
Function<String,String> function = (str)-> str;
String apply = function.apply("111");
System.out.println(apply);

//断定型接口, 返回一个 boolean , test() 方法中输入条件
Predicate<String>  predicate = String::isEmpty;
System.out.println(predicate.test("11"));

//消费型接口, 只有输入,没有返回值
Consumer<String> consumer =new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
};
Consumer<String> consumer1 = System.out::println;
consumer1.accept("111");

//供给型接口,没有输入,只有输出
Supplier<String> supplier = new Supplier<String>() {
    @Override
    public String get() {
        return null;
    }
};
supplier.get();
Supplier<String> supplie1 = ()-> {return "111";};
supplie1.get();

Stream流:

  • 流:流程式处理
  • 对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)
  • public interface Stream<T> extends BaseStream<T, Stream<T>> {}
        // IntStream、LongStream 和 DoubleStream
        // 0~10 0+累加10
        IntStream.rangeClosed(0, 10).parallel().reduce(0, Integer::sum);
		//数组转流
        String[] str = new String[2];
        Arrays.stream(str);
        //快速声明集合
        List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        //数组转集合,集合转数组
        List<String> strings = Arrays.asList(str);
        strings.toArray();
        //创建并行流,虽然效率高,但是是内部多线程处理,注意线程安全
        Stream<String> parallelStream = strings.parallelStream();
        
		 //过滤操作 adminUsers,用户对象集合
		 adminUsers.stream().filter(e -> "何小树".equals(e.getUserName())).collect(Collectors.toList());
		 //结果映射
		 adminUsers.stream().map(AdminUser::getUserName).collect(Collectors.toList());
		 //最大值
		 adminUsers.stream().max(Comparator.comparing(AdminUser::getAge)).get();
		 //截取前两个元素
 		 stream.limit(2).forEach(System.out::println);
 		 //去重
		 stream.distinct().forEach(System.out::println);
		 //去掉,截取掉第一个元素
		  stream.skip(1).forEach(System.out::println);
		  //匹配到某一个就为true
		   boolean flag = stream.anyMatch(s -> s.equals("1"));
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值