类:一类抽象的事务,还不具体。
- 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
类加载过程:
- 加载:将 .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()方法了- 阻塞(
BLOCKED、WAITING、TIMED_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并发包
–常见类:ConcurrentHashMap、CopyOnWriteArrayList、…- 死锁:同一资源被多个线程使用,两个或多个线程都在等待对方释放资源,造成僵持卡死
–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"));

16万+

被折叠的 条评论
为什么被折叠?



