我认为比较详细的java笔记

基本的东西

  Java SE:支持面向桌面级应用的Java平台,提供了完整的Java核心API。

  Java EE:是为开发企业环境下的应用程序提供的一套解决方案。

  Java ME:支持Java程序运行在移动终端上的平台,对JavaAPI有所简化。

  Java Card:支持一些Java小程序(Applets)运行在小内存设备(智能卡)上的平台。

  类C语言、纯粹的面向对象、舍弃C中的指针、垃圾回收功能

  特征:易学的、强制面相对象的、分布式的、健壮的、安全的、体系结构中的(?)、解释型的、性能略高、原生支持多线程的。

  特点:面向对象(概念:类、对象,特性:封装、继承、多态)、健壮性、跨平台性。

  内存泄露(回收不了)和内存溢出还是会出现。

  JDK:Java Development Kit、JRE:Java Runtime Environment。有人问过我,当时比较迷糊,因为我常记各种知识的获取渠道,需要就立马去找。

  JDK = 开发工具集 + JRE;JRE = Java SE标准类库 + JVM;

java概念图描述.PNG

简短的东西

  truefalsenull严格不算关键字,但可以当关键字使用。strictfptransientvolatileassert不完全见过。gotoconst保留字。

byte 1 7
short 2 15
int 4 31
long 8 63
float 4 3.403 38
double 8 1.798 308

  floatdoublelong范围大,因为数|幂

  int a = 128; (byte)a = -128; int a = 129; (byte)a = -127;

  原码取反变反码+1变补码。底层以补码保存。

  instanceof 用过几次。

  >>>空位0补。 ~取反成反码。

  就近原则(脑子里应该有过,很难``遇到,所以没有脑子里多次触发)

1
2
3
4
5
if(x > 2)
if(y > 2)
sout;
else
sout;

  switchbyteshortcharint枚举(5.0)String(7.0)

  default位置是灵活的。会有好玩的效果。

  计算这一年过来多少天:到着走,case 12:这个月的总天数 11 10 9 …… 2 1:日,无需break

  质数:for n % (2 …… n-1) 改进:①非质数。②2……sqrt(n)

  breakcontinue关键字后面不能声明执行语句。(我以前都没考虑过,因为不会这样写。)

  标签lable:continue lable;用得比较少,因为多少靠脑子就可以不要跳多层了。

  空指针:可以用二维数组触发,[1][] -> [0][0]。有人问过我equals的写法,当时我只记得阿里巴巴的手册有写过。

  快排思想:选基数,小的放一边,大的放一边,递归。

  Arrays一些方法equalstoStringfillsortbinarySerach

  面向过程:POP,面向对象:OOP。

  内存解析

  内存解析

以前应该有人问过,忘记该答这个了。

  重载可以出现自动类型提升(int,int)->(double,double)

  5.0可变参数 ,以前是数组。

高级点的东西

  printStream 继承重写下打印,设置给System,可以实现有趣的打印效果。

  类:缺省 public

  MVC:将整个程序分为三个层次:视图模型层、控制器层、数据模型层。

模型层:model主要处理数据。

  • 数据对象封装 model.bean/domain
  • 数据库操作类 model.dao
  • 数据库 model.db

视图层:view显示数据

  • 相关工具类 view.utils
  • 自定义view view.ui

控制层:controller处理业务逻辑

  • 应用界面相关 controller.activity
  • 存放fragment controller.fragment
  • 显示列表的远程适配器 controller.adapter
  • 服务相关的 controller.service
  • 抽取的基类 controller.base

  import static java.lang.System.*;然后out.println(); import static落脚的是类(/接口)里的静态结构。

  重写:权限:子≥父,返回值:void—>void、类—>类or子类,异常:父≥子。

  多态:调用父类声明过的子类方法。属性不适用多态。虚拟方法调用。父类被重写的方法。

  10 == 10.0 == char 10

  单元测试:①类public,②公共无参构造器,③ 方法:public void method(){},④@Test —>org.junit.Test

  三元有类型提升

1
2
Object o1 = true ? new Integer(1) : new Double(2.0);
System.out.println(o1); // 输出 1.0

  多态的理解:

  • 代码的通用性。
  • equals(Object obj)connection
  • 抽象类、接口的使用体现了多态型。

  static可以修饰内部类。

再高级点的东西

设计模式、代码块、抽象类、接口、内部类

  1995年GOF四人组。

创建型:工厂方法、抽象工厂、单例、建造者、原形。

结构性:适配器、装饰器、代理、外观、桥接、组合、享元。

行为型:策略、模板方法、观察者、迭代子、责任链、命令、备忘录、状态、访问者、中介者、解释器。

好多呀。我有一个感觉:Thread用了代理模式。

  java.lang.Runtime用了饿汉的单例。

饿:先造 懒:要才造
对象加载时间长 延迟对象的创建
天然线程安全 简单写法不安全

  以前看过详细的讲解。涉及到反射、序列化,没完全记住😭。主要是混乱。

  一些例子:网站计数器、日志、数据库连接池(用过一点点c3p0,在Apache下的,还有几个类似的,其实就一次)、读取配置的类、Application、win的任务管理器和RecycleBin(回收站)。

  代码块:可以用来初始化。修饰只能用static

  static {}:随类加载执行。{}:对象的创建执行。可以对对象初始化。{}比构造先。(color="#FFB6C1"color="\#FFB6C1"变成绿的了,它是圆盘上旋转180度了吗?添添删删颜色也会变,应该是识别的问题,我猜的)。我说:“有时不要被main迷糊了,它所在的类也要加载”。我还说:“我还看到过premain,好像和agent有关(我不太信),好像和在线调试有关”(全很是怀疑)。

  属性赋值顺序:默认→显示/代码块(看位置)→构造→对象属性,方法。

  子类也可以是抽象类。

  abstract不修饰属性、构造器、私有方法、静态方法、final的方法和类。

  多态的体现:模板方法,用了抽象。像英语作文的模板。比如数据库访问的封装、junit单元测试、servlet的doGet和doPost。

  接口无构造器,接口直接可以多继承。

  代理模式:个人感觉就是一个帮你做事并可以在此前做一些其他事,像VPN、中介的感觉。

  应用场景:

  • 安全代理:屏蔽对真实角色的直接访问。
  • 远程代理:通过代理类处理远程方法调用(RMI 不知道)。
  • 延迟加载

  分类:静态和动态

  工厂:将创建者和调用者分开。如果我没记错的话,BigDecimal就用了工厂,当时我翻源码的时候感觉的,虽然当时懂皮毛。

  JDK7以前public static final 全局常量,JDk8有了静态方法和默认方法。静态方法只能自己用,相当于工具类了。默认方法可以重写。不重写的话,父类和接口都有则父类优先。关于方法的调用:方法名:调用自己的,super.方法:父类的,接口.super.方法:接口的。

  内部类有成员和局部(方法内、代码块、构造器内)之分。对于成员内部类考虑静态和非静态,它们具有/能被/可以:①调用外部类结构。②static修饰。③4种权限。④属性、方法、构造器等。⑤final。⑥abstract。关于外部类的方法可以使用外部类.this.(前面可省略)方法

  对于实例化内部类,静态的可以用new.外部类.外部类(),非静态的可以先new外部类,在用变量.new内部类

  内部类使用方式一(常、标准)、

1
2
3
4
5
6
7
8
9
public comparable getComparable(){
class MyComparble implements Comparable{
@Override
public int compareTo(Object o){
return 0;
}
}
return new MyComparable();
}

  方式二、

1
2
3
4
5
6
return new Comparable(){
@Override
public int compareTo(Object o){
return 0;
}
};

  Integer的内的缓存。Thread内的状态枚举类。

  抽象类和接口大致区别:不能被实例化、都可以被继承(单继承VS多继承)、抽象方法、抽象类有构造器。

  抽象类:InputStream、OutputStream、Reader、Writer内部定义了抽象的read()、writer()方法。

   我听过JDK9时,接口可有私有方法。

  方法的局部内部类

1
2
3
4
5
6
7
8
9
public void method(){
//8以后就省略了,反正都是final,干脆就不写了。
final int num = 10;
class AA{
public void show(){
num.sout;
}
}
}

异常

Throwable类下有Error:虚拟机无法决解的严重问题。StackOverflowError、OOM:new Integer[1024*1024*1024]Exception:一般性问题,可处理。空指针、不存在文件、越界。对于异常,分为受检(checked)异常:编译时和非受检(unchecked)异常:运行时。

checked:

  • IO——read、writer、close
    • FileNotFound——对文件。
  • ClassNotFound

unchecked:

  • 空指针——二维数组可触发,一位数组也可以:null[3]null.方法
  • 越界——abc.charAt(3)
  • ClassCast——我认为向下转型容易触发。
  • NumberFormat——字符串转数字。
  • InputMissMatch——Scanner,我几乎不会遇到。
  • Arithmetic——算术,明着来很难触发,1/0

  几个catch排着的话,异常顺序为子子……父

  常见的方法:e.getMessage()e.printStackTrace()。我认为如果开发中是不是要结合Log。

  即使有finallytrycatch也可以有returnfinally里的return大。

  重写的话,异常类型:父≥子,父没有抛出,则子类只能try。例子:run方法。

  对于递进的方法,一般抛出,外面try

  try还可以看到无catch的情形。

  自定义异常类的步骤:①继承。②序列号serialVersionUId。③一般两个构造器()(String msg)

我和它之间还有些朦胧的东西,它有面纱。

线程相关

基本概念等小东西

  程序:为完成任务,指令的集合。

  进程:已经运行的一个程序。

  线程:一个程序内部的一条执行路径。调度和执行的单位,有独立的运行栈和程序计数器(PC)。

  一个Java程序至少有三个线程:mian(),gc,异常处理。

  我听过:Java的线程是一对一的,Go的是多对多的,K开头的那个东西帮Java弄成多对多的。

  并行:多个CPU同时执行多个任务。

  并发:一个CPU(时间片)同时执行多个任务。

多线程的优点:

  1. 提高应用程序的响应,对图形化界面更有意义,可增强用户体验。
  2. 提高CPU的效率。
  3. 改善程序结构,利于理解和修改。

前两种创建线程的方式

Thread

  步骤:继承Thread,重写run,创建对象,调用start()

  如果直接调用run(),则相当于直接调用方法,还在同一个线程内。

  不可多次start(),因为状态会报异常。

  Thread的部分方法,注意witenotifynotifyAll在Object里。(至于为什么在这里面,我想应该是同步监视器调方法的原因。)

  • start、run。
  • currentThread——静态,得到当前线程。
  • getName
  • setName——创建是也可以取名字。
  • yield——释放当前CPU的的执行权。
  • join——其他线程调用join,当前线程进入阻塞状态(有异常),直到调用join的线程结束才有机会。
  • stop——过时了,如其名。
  • sleep——lang的毫秒,有异常,静态。
  • isAlive——当前线程是否存活。(我听过:有个框架对于“is”开头的方法,处理(我猜是反射)会有问题。)

  线程的调度策略有时间片和抢占式:高优先级的线程抢占CPU。Java的方法是同优先级的用先进先出、时间片,高优先级的是使用优先调度的抢占式策略。

关于优先级:

  • MAX——PRIORITY:10
  • MIN——PRIORITY:1
  • NORM——PRIORITY:5

Runnable

  实现Runnable接口,创建对象传入Thread,这里提现了多态。(应该是Threnad(Runnable target))

  这种方式方便卖票。

  优先选择这个,它没有单继承的局限性,可以共享数据。

分类和周期

  Java线程分为守护线程和用户线程。在start()调用前调用setDaemon(true)就可用户线程变守护线程。gc就是典型的守护线程。

线程状态转换图.png

线程安全问题

  利用同步机制

同步代码块

  synchronnized、synchronized、synchronizeds、synchronized、synchronized、synchronized

1
2
3
synchronized(同步监视器){
操作共享数据的代码
}

  同步监视器:锁:任何一个类的对象。

  多个线程公用一把锁。

  Runnable可以用this,继承的方式可以用类.class。推出类也是对象Class clazz = 类.class类.class只会加载一次。

同步方法

  用synchronized修饰。非静态的锁是this,非静态的锁是当前类本身

Lock锁——JDK5.0

  Lock本身是一个接口,我们使用它的一个子类ReentrantLock,参数可以是一个boolean,ture的话是公平的Lock。

  1. 实例化Lock,new ReentrantLock()
  2. 把要处理的代码放到try里。
1
2
3
4
5
6
try{
//调用lock()方法
实例Lock.lock();
}finally{
实例Lock.unlock();
}

  感觉可以应用模板方法。

  synchronizedlock的异同:都可以解决线程安全问题。synchronized在执行相应的同步代码以后,自动地释放锁。lock需要手动启动同步,结束同步也需要手动实现。

  建议:lock→同步代码块→同步方法。其实谁都可以。

其他

单例修改:

1
2
3
4
5
6
synchronized(类.class){
if(instance == null){
intstance = new 构造();
}
return instance;
}

效率差些

1
2
3
4
5
6
7
if(instance == null){
synchronized(类.class){
if(instance == null){
intstance == new 构造();
}
}
return instance;

效率高些

  死锁:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了死锁。

  一种可能形成死锁的方式

1
2
new Thread(){两个synchronized,两个锁嵌套}.start();
new Thread(new Runnable(){两个synchronized交换锁嵌套}).start();

线程的通信

  wait():会释放锁。notify():唤醒一个被wait的线程,喂,起来搬砖了。notifiyAll:唤醒所有被wait的线程。要在synchronized块里或者synchronized方法里,lock用的别的方式。

  如果在外面另外声明一个唯一的对象,比如obj。此时

1
2
3
4
synchronized(obj){
this.notify();//非法的monitorState
……
}

  所以上面的方法,调用者必须是同步代码块或同步方法的同步监视器。

`sllep()`和`wait()`异同
当前线程进入阻塞状态
在Thread类 在Object类
几乎无限制 synchronized代码块和synchronized方法内,由同步监视器调用
不会释放锁 释放锁

后两种创建线程的方式

Callable——有泛型

  可以有返回值、方法可以抛出异常、支持泛型的返回值。不过有些需要借助FutureTask类,比如获取返回结果。

1
2
3
4
5
6
class CallableExample implements Callable {
@Override
public Object call() throws Exception {
……
}
}

  Future接口可以对具体Runnable、Callable任务的执行结果进行取消、查询是否完成、获取结果等。FutureTask是Future接口的唯一实现类,有泛型。FutureTask同时实现(间接)了Runnable、Future接口。它既可以作为Runnable被线程执行,又可以作为Future对到Callable的返回值。

  从列子里得到步骤

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
public class TestCallable {

public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();

//1.执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。
FutureTask<Integer> result = new FutureTask<>(td);

new Thread(result).start();

//2.接收线程运算后的结果
try {
Integer sum = result.get(); //FutureTask 可用于 闭锁
System.out.println(sum);
System.out.println("------------------------------------");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}

class ThreadDemo implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i <= 100000; i++) {
sum += i;
}
return sum;
}
}

  创建实现Callable的类,实现Call方法,创建对象。创建FutureTask对象。用Thread接收Callable实现类对象并start。用FutureTask的get得到返回值。

  Callable比Runnable强大的原因:call()有返回值、call()可以抛出异常、支持泛型。

线程池

  当经常创建和销毁,使用量特别大的资源:并发。

  好处就是:提高响应速度(减少创建新线程的时间)、降低资源消耗(重复利用)、便于管理。

  5.0:ExecutorService真正的线程池接口。常见子类ThreadPoolExecutor。

  • void execute(Runnable command):执行任务/命令,没有返回值。一般用来执行runnable。
  • <T> Future<T> submit(Callable<T> task):执行任务,有返回值。一般用来执行callable。
  • void shutdown():关闭连接池。

  Executors工具类,线程池的工具类,用于创建并返回不同类型的线程池。

  • Executors.newCacheThreadPool():创建一个可根据需要创建新线程的线程池。
  • Executors.newFixedThreadPool(n):创建一个可重用固定线程数的线程池。
  • Executors.newSingleThradExecutor():创建一个只有一个线程的线程池。
  • Executors.newScheduledThradPool(n):创建一个线程池。它可以安排在给定延迟后运行命令或者定期地执行。
1
2
3
4
5
6
//多态
//后面其实是ThreadPoolExecutor
ExecutorService service = Executors.newFixedTheadPool(10);
service.execute(Runnable实现类对象);
service.submit(Runnable或Callable实现类对象);
service.shutdown();

常用类

String

  final类,implements了java.io.SerializaleComparableCharSequence。用final char[] value存储字符串数据。其中new在堆,""在字符常量池。

  • new String()——this.value = new char[0]; "".value;
  • new String(original)——this.value = original.value
  • new String)(char[])——this.value = Arrays.copyof(vallue,value.length)

  一个人类,P1.name.equals(P2.name) == trueP1.name == P2.name == true

  "A" + "B" = "AB"涉及到变量名的组合,在堆里,相当于new。final的变量("A") + "B" = "AB"

  intern()返回常量池已经存在的,没有就添加。> 返回字符串对象的规范表示。

  一些方法:length()charAt()isEmpty():return value.length == 0;toLowerCase()toUpperCase()trim()equals(obj)euqalsIgnorecCase(str)concat(str)↔"+"comapreTo(str)substring(begin)substring(begin,end) [)contains(CharSequence s)indexOf(str)indexOf(str,index)rreplace(oc,nc)replace(CahrSequence target,CharSequence replacement)repalceAll(regex,replacement)repalceFirst(regex,repalcement)matches(regex)splittoCharArray

  • endWith(str):是否以str结束。
  • startWith(str):是否以str结束。
  • startWith(str,index):是否是子串的开始。
  • last类别两个index:反向搜索。

  转换成字符数组:str.getByte()默认字符集,("gbk")使用GBK。复习:936——GBK,65001——utf8。

StringBuffer和StringBuilder

  都是可变的。StringBuffer线程安全,效率低。StringBuilder线程不安全,效率高。都是char[]

  new StringBuffer()new char[16]

  new StringBuffer(str)new char[str.length + 16]

  lengthcount

  默认扩容是原容量的2倍+2。

  一些方法,append(xxx)有返回,方法链。delete(start,end)replace(start,end,str)insert(offset,xxx)reverse()indexOf(str)substring(start,end)lengthcharAt()setCahrAt(n,ch)

1
2
3
4
5
6
7
8
String str = null;
StingBufer sb = new StringBuffer();
sb.append(str);
sb.len == 4;
sb "null";

//异常
StringBufer sb1 = new StringBuffer(str)

字符常量池

  1.6 方法区(永久区)

  1.7 堆空间

  1.8 方法区(元空间)

8之前的日期和时间API

System的和Date

  System.currentTimeMillis()单位毫秒,从1970年开始,long型。

  java.utils.Date不利于国际化。有两个构造器()(long),有两个方法toString()getTime() 毫秒数。它的子类java.sql.Date对应数据库的日期变量。它的构造器(long),另一个无了。

  java.util.Date向下转型到java.sql.Date,也可以通过getTime()进行new出。

java.text.SimpleDateFormat

  不与语言有关的方式来格式化和解析日期。

  SimpleDateFormat():默认模式和语言环境,也可以用SimpleDateFormat(pattern)来指定pattern格式。通过format(Date date)来格式化时间对象。通过Date parse(String sourse)来解析字符串。

  简单使用:

1
2
3
4
5
6
7
8
SimpleDateFormat sdf = new SimpleDateFormat();
Date d = new Date();
String str = sdf.format(d);//19-2-18 上午 11:48
Date d1 = sdf.parse(str);

sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
str = sdf.format(d);
d1 = sdf.parse(str);

  字符串时间转java.sql.Date:先得到java.util.Date,在通过getTime()生成。

Calendar 日历

  1.1加入,弃用Date,但并不好多少。java.util.Calendar抽象类。通过Calendar.getInstance()得到实例,通过getClass发现其实是子类GregorianCalendar

  一些方法:get(field)多种field,比如Calendar.DAY_OF_WEEK,多种set(XXX),还有add(XXX),还有getTime DatesetTime(Date)

  注意,月份是从0开始,星期是日到六。

8中新的

  因为一些问题:

  • 可变性:日期时间这些类应该是不可变的(Calendar)。
  • 偏移性:Date年从1900开始,而月份从0开始。
  • 格式化:只对Date有用,Calendar不行。
  • 线程不安全,不能处理润秒。

  java,time吸收了Joda-Time的精华。包含了LocalDateLocalTimeLocalDateTimeZoneDateTime和持续时间(Duration)。

  Date用toInstant()转换成Instant

  • java.time :包含值对象的基础包。
    • chrono :提供不同的日历系统的访问。
    • format :格式化和解析时间和日期。
    • temporal :包括底层框架和扩展特性。
    • Zone :包含时区支持的类

  多数使用timeformat,可能使用temporal

  now()创建对象,LocalDate.now()LocalTime.now()LocalDateTime.now(),可以加上时区。

  of()可以指定,LocalDateTime.of(2020,10,6,13,23,43)

  getXXX()比如getDayOfMobthgetMonth

  withXXX(XXX)进行设置,有返回值,新的对象。

  plusXXXminusXXX减。

Instant 瞬时

  1970年1月1日0时0分0秒,UTC,类似与Date。因为java.time包是基于纳秒计算的,所有Instant可以到达纳秒级。

  now()默认UTC的Instant类的对象。

  ofEpochMilli(long)1970上加上指定毫秒的Instant对象。

  对象.atOffset(ZoneOffset offset)结合即时的偏移来创建OffsetDateTime对象。ZoneOffset.ofHours(8)

  对象.toEpochMilli即时间戳。

格式化

  DateTimeFormatter有三种格式化方法。

  1. 预定义的标准格式

    ISO_LOCAL_DATE_TIMEISO_LOCAL_DATEISO_LOCAL_TIME用DateTimeFormatter点上就可创建对象。

  2. 本地化相关的格式

    ofLocalizedDateTime(FormatStayle.LONG) 还有MEDIUMSHORT。用DateTimeFormatter点上就可创建对象。

    ofLocalizedDate(FormatStyle.LONG)多一个FULL

  3. 自定义格式

    ofPattern("yyyy-MM-dd hh:mm:ss")。用DateTimeFormatter点上就可创建对象。

  都有formatparse方法。

比较

  Comparable,自然排序。当this >obj,返回+;当this<obj,返回-;当this=obj,返回0。

  Arrayss的sort是升序。在使用时也可以利用一些包装类的compare方法。

  Comparator,定制排序,里面有很多静态方法。当不方便修改代码时或已经实现的不适合时,可用。实现compare方法,还可以有泛型。

System

  String getProperty(String key)获取属性。

常见的

key 说明
java.version 如其名
java.home java的安装目录
os.name 系统的名称
os.version 系统的版本
user.name 用户名
user.home 用户主目录
user.dir 当前工作目录

Math

  long round(double a)toDegreestoRadians

BigXXX

  BigInteger不可变的任意精度整数。

  BigDecimal不可变的任意精度有富豪十进制定点数。

好玩的东西

枚举

  类的对象只有有限个,确定的,称此类为枚举类。一组常量,建议使用枚举类。如果只有一个对象,可以作为单例模式的实现方式。

  jdk5.0前的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Season {
//声明属性
public final String SeasonName;
public final String SeasonDesc;

//私有构造器
privite Season(String neme, String desc) {
this.SeasonName = name;
this.SeasonDesc = desc;
}

//提供枚举类的多个对象
public static final Season SPRING = new Season("春天", "春天在哪里");
public static final Season SUMMER = new Season("夏天", "宁夏");
public static final Season AUTUMN = new Season("秋天", "秋天不回来");
public static final Season WINTER = new Season("冬天", "大约在冬季");

//其他诉求
public String toString() {
return "全年都在 弹棉花";
}
}

  另一种定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
enum Season {
//提供当前枚举类对象
SPRING("春天", "春天在哪里"),
SUMMER("夏天", "宁夏"),
AUTUMN("秋天", "秋天不回来"),
WINTER("冬天", "大约在冬季");

//声明属性
public final String name;
public final String desc;

//构造器
privite Season(String name, String desc){
this.name = name;
this.desc = desc;
}

//其他诉求
//toString可不重写,sout或输出对象名。
//说明父类不是Object,而是java.lang.Enum。
}

  Enum类的常用方法:

方法名 描述
toString() 返回对象名。
valueOf(objname) 根据提供的objname,返回与objname同名对象。异常:非法参数。
values() 返回对象数组。(我发现不在API里,查https://www.pianshen.com/article/9971363552/)
equals 可以用”==“判断枚举常量相等。本身也是”==“。
hashCode 为了和equals保持一致。不可变。
getDeclaringClass 得到所属枚举类型的class对象,用了判断两个枚举常量。
name 建议优先使用toString。
ordinal 得到当前枚举常量的次序。
comapreTo 大小(声明顺序排列)
clone 枚举不能clone。防止子类实现clone。ENUM实现了一个仅抛出不支持clone的 异常的不变clone。

The compiler automatically adds some special methods when it creates an enum. For example, they have a static values method that returns an array containing all of the values of the enum in the order they are declared. This method is commonly used in combination with the for-each construct to iterate over the values of an enum type. https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

  实现接口有两种,第一种,没啥可说的。第二种,让枚举对象分别去实现SPRING("春天"){实现方法}

注解

  JDK5.0增加了对元数据(metedata)的支持——注解。可用于修饰类、构造器、方法、成员变量、参数、局部变量的声明。

  在SE中,注解存在的目的比较简单。在EE/Android中是重要角色,代替EE旧版中遗留的繁冗代码和xml配置。一定程度上,框架 = 注解 + 反射 + 设计模式。

  示例:生成文档相关。authorversionsee参考转向、since从哪个版本开始增加、param 参数类型 说明return 类型 说明exception 类型 说明

  示例:编译时进行格式检查。JDK内置的三个基本注解:OverrideDeprecatedSuppressWarringsunusedunchecked等。

  示例:跟踪代码依赖性,实现替代配置文件功能。Servlet3.0使得不再需要在web.xml进行servlet配置@WebServletd("/login")

  示例:Spring中的事物管理。@Transactional(propagation=propagation.REQUIRES_NEW,isolation=isolation.READ_COMMITTED,readonly=false,timeout=3)

  示例:单元测试。timeout=1000超时时间,超过时间测试失败。expected=Expection.class声明会发生的异常。配合@Test使用的,单独用无意义的有:

  • @BeforeClass静态方法,只执行一次,类初始化时执行。
  • @AfterClass静态方法,只执行一次,所有方法完成后执行。
  • @Before 非静态方法,在@Test前,每一个@Test都会执行。
  • @After非静态方法,在@Test后,每一个@Test都会执行。
  • @Ignore不参与测试的方法上。

  自定义的话,参照SuppressWarraings。

1
2
3
public @interface MyAnnotation {
String value() default "搬砖";
}

  自动继承java.lang.annotation.Annotation接口。成员变量以无参方法的形式来声明,类型可以有八种基本数据类型、String、class、enum、Annotation和以上对应数组。成员变量可以指定初始值,用default。如果只有一个参数成员,建议使用value。没有成员定义的称为标记。配上注解的信息处理流程才有用意义。

元注解

  JDK提供4种元注解用来修饰其他注解,解释说明。

  @Retention(XXX)指定声明周期,有一个枚举类RetentionPolicy。SOURCE源文件有效,编译器直接丢弃这种策略的注释。CLASS在class文件有效,运行java程序时,JVM不会保留注解。这是默认值。RUNNTIME运行时有效,运行java程序时,JVM会保留注释,程序可以通过反射获取该注解。

  @Target(value={ElementType.XXX……})指定能用于哪些程序元素。CONSTRUCTORFIELD域、LOCAL_VARIABLE局部变量、METHODPACKAGE包,比较特殊的感觉、PARAMETER参数、TYPE类,接口(包含注解类型),enum的声明。

  自定义注解一般都会用Retention和Target。

  频率低的注解,一般不会用。在下面。

  @Documented将被javadoc提取成文档。默认javadoc无注解。此时Retention值为RUNTIME。

  @Inherit使具有继承性。类被注解,子类自动有注解。实际应用中,使用较少。

  反射获取注解信息。

1
2
3
Class<Demo> clazz Demo.class;
Annotation[] annotataions = clazz.getAnnotations();
遍历打印一下

JDK8的注解新特性

可重复注解

  以前的方式。一个MyAnnotation,一个MyAnnotations{MyAnnotation[] value();}。用@MyAnnotations({@MyAnnotation(value="XXX"),@MyAnnotation(value="XXXX")})

  现在。新的注解@Repeatable(MyAnnotations.class)。要求MyAnnotation和MyAnnotations的Target、Retention等元注解一致。用@MyAnnotations(value="XXX") @MyAnnotations(value="XXXX")……

类型注解

  class Demo<注解 T>{}Target要有TYPE_PARAMETER。能写在类型变量的声明语句中,比如泛型声明。

  throws 注解 异常类名ArrayList<注解 String>int num = (注解 int)10L;Target要有TYPE_USE。能写在使用类型的任何语句中。

  反射能拿到。

大头但也好玩

集合

  可以分为Collection和Map两大体系。

flowchart BT;
subgraph iterator [ ]
a1[ListIIterator] --继承-->a2[terator];
end

a3[Collection 单列 存对象] --获取-->iterator;

a4[List 接口 有重 类似动态数组] --继承-->a3;
a4 --获取--> iterator;
a6[Vector] -.实现.-> a4;
a7[ArrayList] -.实现.->a4;
a8[LinkedList] -.实现.->a4;
Stack -.继承.-> a6;

a5[Set 接口 不重 类似数学集合] --继承-->a3;
a9[HashSet] -.实现.->a5;
a10[SortedSet] --继承-->a5;
a11[LinkedHashSet] --继承-->a9;
a12[TreeSet] -.实现.->a10;
flowchart BT;
Hashtable -.实现.-> Map;
HashMap -.实现.-> Map;
SortedMap --继承--> Map;

Properties --继承--> Hashtable;
LinkedHashMap --继承--> HashMap;
TreeMap --实现--> SortedMap;

  Hashtable没错。

Collection接口部分API

  add(obj)size()addAll(Collection coll)isEmpty() size==0clear()contains(Object obj)用的equals、containsAll(Collection c)remove(Object obj)removeAll(Collection c)差集,去掉共同部分、retrainAll(Collection c)相当于交集、equals(Object o)hashcode()

  得到Collection可以用Arrays.asList(T... a),变成数组可以用toArray()。小心Arrays.asList(new int[]{123,456}),会吧数组当成一个元素。可以Arrays.asList(123,456)或者intInteger

  iterator()返回Iterator接口实例。迭代器模式:提供一种方法访问容器对象中各个元素而不需要暴露该对象的内部细节。迭代器过多next()NosuchElementException。每次遍历都要重新生成迭代器。迭代器对象.remove()删除元素。未调用next()或上次next调用了remove,再调用remove,会IllegalStateException

List

  ArrayList、LInkedList、Vector的异同。都实现了List接口,有序,可重复。

  • ArrayList 作为List的主要实现类 1.2 效率高 线程不安全。Object[] elementData
  • Vector 作为List的古老实现类 1.0前朝的臣子 效率低 线程安全。Object[] elementData
  • LinkedList 其次的 双向链表存储 频繁地插入和删除比ArrayList效率高。

  反源码看到的modCount++,涉及快速失败机制。

7与8

ArrayList

  ()→10的Object[] elementData。扩容1.5倍。

  add(123)→elementData[0] = new Integer(123)。

  不够时扩容,同时复制原来数据。

  建议使用带参构造器。

  8中代码修改了,注释没改。第一个add时才创建10的数组。()→{},add判断{}是否取得最大容量,后续无异。

  7类似于饿汉。8类似于懒汉,延迟数组的创建,节省内存。

LinkedList

  没什么,就是为了虚假的强迫症。node体现双向链表。

Vector

  78()→(10),扩容2倍。为了安全也不愿意用Vector,有collections的synchronizedList得到一个安全的。

List的一些方法

  • add(index, o)
  • addAll(index, coll)
  • get(index)
  • indexOf(o)
  • lastIndexOf(o)
  • Object remove(index) 和Collcetion的Object remove(o)
  • Object set(index, o)
  • sublist(from, to)

一个关于LIst的题

1
2
3
4
5
6
7
8
9
10
11
12
public void testListRemove() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
updateList(list);
System.out.println("list = " + list);
}

private void updateList(List list) {
list.remove(2);
}

Set接口

没有定义新的方法。

  • HashSet:set接口主要实现类,不安全,null值。
  • LinkedHashSet:HashSet子类,遍历内部数据可以按照添加的顺序。
  • TreeSet:红黑树,可以按照对象指定属性进行排序。

Set无序性≠随机性。以HashSet为例,存储的数据在底层数组中并非按照数组索引顺序添加而是根据Hash值。

不可重复性要用equals和hashcode。

底层是数组+链表。

向Set添加数据,一定要重写hashcode和equals。

一致性:相等的对象必须具有相等的散列码。

HashSet和HashMap有关系:HashSet里在new HashMap<>()

LinkedHashSet

LinkedHashSet感觉图.png

频繁遍历比HashSet高。

TreeSet

数据要是相同类对象。

1
2
add 123 456 "AA"  ClassCastException
数字从小到大

自然排序中,相同用compareTo判断是否相同。相同返回0。

红黑树,查询速度比List快。

new TreeSet(Comparator com)定制排序。判断相同用compare,相同返回0。

HashSet

1
2
3
4
5
6
7
8
9
10
11
12
一个Persion,重写了equals和hashcode。

p1 (1001, “AA”)
p2 (1002, "BB")
set.add(p1) set.add(p2)
p1.name="CC" //hashcode变了
set.remove(p1) //删不了
sout 有两个
set.add(new P(1001, "CC"))//我:成功,因为位置不一样。
sout 有三个
set.add(new P(1001, "AA"))//我:位置相同但equals不一样。
sout 有四个

对应

为什么不讲源码就是因为。

graph TB;
HashSet --对应-->HashMap
LinkedHashSet --对应--> LinkedHashMap
TrssSet --对应--> TreeMap

Map

  • HsahMap:Map的主要实现类,不安全,效率高,null的key和value。
    • LinkedHashMap:保证在遍历时,按照添加顺序遍历。
  • TreeMap:红黑树,保证按照添加的key-value对进行排序,实现排序遍历(key)。
  • Hashtable:Map的古老实现类,安全,效率第,不能null的key和value,会空指针。
    • Properties:配置文件,key和value都是String。

put的是Entry,Entry有key和value,也是无序不可重复,使用Set存储所有Entry。

key是无序的,不可重复的,使用Set存储所有的key。

value是无序的,可重复的,使用Collection存储所有的value。

Map结构的理解.PNG

  针对上图,此时我还没翻源码,但我想到的一种可能:内部类或者内部接口。

以HashMap为例,key要equalshashcode,value要equals

HashMap

实现原理
  • 7

    1
    2
    3
    4
    5
    6
    7
    8
    HsahMap map = new HashMap();// 长度是16的一位数组Entry[] table。
    ……
    map.put(k,v);
    /*
    计算key的hash值,与上数组长度-1得数组位置。
    空则加入成功,不空则比较hash值。
    不同则加入成功,同则比较equals,true则替换value,false则加入成功。
    */

    扩容:2倍,复制。

    HashMap存储结构7.PNG

  • 8

    1
    2
    3
    4
    new HashMap();//没有创建16的数组。数组不加Entry,叫node。
    /*
    首次put创建长度16的数组。当数组的某个位置上的元素以链表形式存在的数据个数>8,且数组长度>64时,此时此索引位置上的数据改为使用红黑树存储。
    */

    HashMap存储结构8.PNG

  • 7的码

    1
    2
    3
    4
    while(capacity < 16)
    capacity <<= 1;//变2的多少幂

    hash&(length-1)//length-1转成二进制数,基本就明白了吧
  • 其他和量

    put返回旧值/null,曾经做leetcode的一个题里,有人利用到了这个,真是太棒了。

    超临界值且要存放的位置非空时,扩容,2倍。

    名称 描述
    DEFAULT_INITIAL_CAPACITY 默认容量16
    MAIMUM_CAPACITHY 支持最大扩容2^30
    DEFAULT_LOAD_FACTOR 默认加载因子0.75
    TREEIFY_THRESHOLD Bucket中链表长度大于改默认值,转化为红黑树
    UNTREEIFY_THRESHOLD Bucket中红黑树存储的Node小于该默认值,转化为链表
    MIN_TREEIFY_CAPACITY 桶中的Node被树化时最小的hash表容量。(当桶中Node的数量大到需要变红黑树时,若hash表容量小于MIN_TREEIFY_CAPACITY时,此时应执行resize扩容操作这个MIN_TREEIFY_CAPACITY的值至少是TREEIF_THRESHOLD的4倍。)
    table 存储元素的数组,总是2的n次幂
    entrySet 存储具体元素的集
    size HashMap中存储的键值对的数量
    modCount HashMap扩容和结构改变的次数(我:快速失败机制)
    threshold 扩充临界值
    loadFactor 填充因子

LinkedHashMap

  HashMap的子类,重写了newNode。

  内部类

1
static class Entry extends HashMap.Node<K,V>

  HashMap的内部类

1
static class Node<K,V> implement Map.Entry<K,V>

  当时看到这里,产生了内部接口的概念,查了一下,有相关的东西。

Map的一些方法,以HashMap为例

  Object put(ok,ov)void putAll(Map m)Object remove(ok)void clear()get(ok)boolean containsKey(ok)boolean containsValue(ov)size()isEmpty()equals(o)Set keySet()Collection values()Sete entrySet()

Collections工具类

  操作Set、List、Map的工具类。

  • 排序

    reverse(list)shuffle(list)sort(list)sort(list,comparator)swap(list,int,int)

  • 查找替换

    Object max(coll)Object max(coll,comparator)min 同理int frequency(coll,obj)ob次数void copy(List dest,List src) src复制到dest(List dest=Arrays.asList(new Object[src.size)()]))boolean replaceAll(List<T> list,T old, T new)新的换所有旧值synchronizedXXX()

泛型,不大但按顺序放这里

  容器设计阶段和声明阶段不能确定到底存什么类型对象,所以1.5前只能把元素类型设计为Object。1.5后用泛型解决。

  ClassCastException:XX→O→XX。

  1.5接口、集合、集合类都修改为带泛型的结构。

  实例化时未指明泛型,默认Object类型。

切不可轻视初学者,轻视他人有无边无量的罪。下下人有上上智,上上人有没意志。——慧能

  自定义泛型结构class Demo<T>{ T orderT ;},定义了泛型实例化时建议带上。子类继承时,可以指明。指明后子类就是普通类。子类继承可以部分保留分类的泛型。

1
2
3
ArrayList<String> list1 = null;
ArrayList<Integer> list2 = null;
//list1 list2不能相互赋值

  在类/接口上声明的泛型,在静态方法中不能使用类的泛型。异常类不能是泛型。

  不能使用new E[],但可以E[] eles = (E[])new Object[capacity]。(不太好吧。)

  泛型方法:在方法总中出现了泛型的结构,泛型参数与类的泛型参数没有关系。→泛型方法所属的类是不是泛型类都没有关系。可以是静态的,泛型参数调用时确定。

1
public static <E> List<E> arrayToList(E[] arr){} 

  通配符:?(数据库占位符)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
List<Object> list1 = null;
List<String> list2 = null;
List<?> list = null;
list = list;
list = list2;

list<String> list3 = new ArraysList<>();
list3.add("AA");
list3.add("BB");
list3.add("CC");
list = list3;
list.add("不能添加数据");
list.add(null);

Object o = list.get(0);//总归是Object的子类

  对于List<?>不能向其添加数据但null可以加。

  有限制条件的通配符:<? extends Person>:上限Persion,<? super Persion>:下限Persion。

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
List<? extends Persion> list1 = null;
List<? super Persion> list2 = null;

List<Student> list3 = null;
List<Persion> list4 = null;
List<Object> list5 = null;


list1 = list3;
list1 = list4;
list1 = list5;//不行

list2 = list3;//不行
list2 = list4;
list2 = list5;

//读取
//假设上面都赋值了
list1 = list4;
Object o = list1.get(0);
Persion p = list1.get(0);

list1 = list3;
Persion p = list1.get(0);
Student s = list1.get(0);//不行 得到的可能比Persion小,为了包含所有,要取大的,相当于上确界。

list2 = list4;
Object o = list2.get(0);//只能是Object 得到的可能比Persion大,但再大大不过Object。


//写入 要理解多态
list1.add(new Student());//不行

list2.add(new Persion());
list2.add(new Student());

IO流

File

  可以是文件也可以是目录,在java.io下。它的构造器有File("233.txt")File("parent","child")File(File parten, "child")File(URI uri)

  对于分隔符,windo和DOSs用\,UNIX和URL用/,为了跨平台,File类提供一个常量public static final Sting separator来分割。

  • 获取功能

    getAbsolutePath()getPath()getName()getParent()上层文件目录路径,无则null、long length()lastModified()最后一次修改时间。文件不在也不会报错

    String[] list()File[] lastFile()

  • 重命名功能

    boolean renameTo(File dest)重名为指定的文件路径。要成功的话,调用者要在硬盘存在,dest不能存在。可以文件移动、重命名、修改文件夹名称。

  • 判断功能

    isDirectory()isFile()exists()canRead()canWrite()isHidden()。不存在时,要注意

  • 创建功能

    boolean creatNewFile()存在则不创建,返回false、boolean mkdir()存在则不创建,上层目录不存在也不创建、boolean mkdirs()

  • 删除功能

    delete()不走回收站。

IO流

  input和output相对于(内存)程序而言。

分类:

  • 字节流(8bit),字符流(16bit)。

  • 输入流,输出流。

  • 节点流,处理流。(大部分教什么大水管套小水管,根本不好理解,反而节点流、处理流好理解多了。)

    (抽象基类) 字节流 字符流
    输入流 InputStream Reader
    输出流 OutPutStream Writer

  java的IO流共涉及40多个类,都是从抽象基类派生的。

分类 字节输入流 字节输出流 字符输入流 字符输出流
抽象基类 InputStream OutputStram Reader Writer
访问文件(节点流) FileInputStream FileOutputStram FileReader FileWriter
访问数组 ByteArrayInputStream ByteArrayOutputStram CharArrayReader CharArrayWriter
访问管道 PipedInputStream PipedOutputStram PipedReader PipedWriter
访问字符串 StringReader StringWriter
缓冲流 BufferedInputStream BufferedOutputStram BufferedReader BufferedWriter
转换流 InputStreamReader OutputStramWriter
对象流 ObjectInputStream ObjectOutputStram
FilterInputStream FilterOutputStram FilterReader FilterWriter
打印流 PrintStream PrintWriter
推回输入流 PushbackInputStream PushbackReader
特殊流 DataInputStream DataOutputStram

FileReader和FileWriter

  read()返回一个字符(int),如果到达文件末尾,返回-1。read(char[] cbuf)返回读入数组的字符个数。read(char[] cbuf, int off, int len)很少用。

  输出时,如果文件不存在会自动创建文件,如果文件存在,当FileWriter(file,append:false)时(默认覆盖),覆盖,当FileWriter(file,append:true)时,追加。

FileInputStream和FileOutputStram

  处理文本文件(读),可能出现乱码。复制到是可以。

  关闭外层流的同时內层流也会自动关闭。

缓冲流

  一种处理流。提高了速度。

  缓冲8192,8kb。

  flush()刷新缓冲区。

  BufferedReader有String readLine(),到末尾返回null。不包含换行符,可以用newLine()

转换流

  字节流和字符流之间的转换。编码解码。

转换流.PNG

1
2
3
4
5
6
7
8
9
try(InputStreamReader isr = new InputStreamReader(new FileInputStream("233.txt"), "UTF-8")){
char[] cbuf = new char[20];
int len;
while((len = isr.read(cbuf)) != -1){
System.out.print(new String(cbuf, 0, len));
}
}catch (IOException e){
e.printStackTrace();
}

标准输入输出流

  System.in标准输入流,默认键盘输入,类型是InputStream。System.out标准输出流,默认从控制台输出,类型是PrintStream,是OutputStream的子类。通过setInsetOut进行重定向。

  一个题目键盘读入转大写输出,e或exit退出。①Scaner,②

1
2
3
4
5
6
7
8
9
10
11
12
13
14
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
System.out.println("请输入你要转换的字符:");
while (true) {
String data = br.readLine();
if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)) {
System.out.println("欢迎下次再用,再见!");
break;
} else {
System.out.println(data.toUpperCase());
}
}
} catch (IOException e) {
e.printStackTrace();
}

打印流

  实现将基本数据类型的数据格式转化为字符串输出。

打印流:PrintStream和PrintWriter。

  • 提供了一系列重载的printl()println()方法。
  • 不会抛出IOExcepiton。
  • 有自动的flush功能。
  • 打印所有的字符都使用平台默认的字符编码转换为字节。在需要写入字符而不是字节的情况下,应该使用PrintWriter类。
  • System.out返回的是PrintStream的实例。

数据流

  DataInputStream和DataOutputStram,为了方便得操作java的基本数据类型和String(字节数组)。

  • DataInputStream的方法

    XXX readXXX()String readUTF()void readFully(bute[] b)

  • DataOutputStram的方法

    read改成write。

  (EOF异常)

  (IO流体现装饰器设计模式)

对象流

  用于存储和读取基本数据类型数据或对象的处理流。

  序列化和反序列化。

  不能序列化static和transient修饰的成员变量。

1
2
3
4
5
6
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("233.dat"))) {
oos.writeUTF("修身养性");
oos.flush();//必须要显示写吗?有什么道道吗
}catch (IOException e){
e.printStackTrace();
}

  方法我我认为和数据流的差不多。

自定义序列化

  实现Serializable或Extrenailzable接口之一(NotSerializableException)。需要一个全局常量public static seriaVersionUTD用来表明类的不同版本的兼容性。没有显示定义的话,它的值是java运行时根据类的内部细节自动生成的。没写的话,类变了,反序列化会报错。保证内部属性也必须是可序列化的。

RandomAccessFile

  在java.io下,直接继承与java.lang.Object。实现了DataInput和DataOutput,可读可写,还是要两个。支持“随机访问”的方式。程序可以直接跳到文件的任意地方读写文件。支持只访问文件的部分内容。包含一个记录指针来标记当前读写位置。long getFilePointer()得到位置,void seek(long pos)定位到pos位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
try (RandomAccessFile raf1 = new RandomAccessFile("src\\女神.tif", "r");
RandomAccessFile raf2 = new RandomAccessFile("src\\女神1.tif", "rw")) {
/*
mode访问模式
r只读 不创建文件
rw 不存在则创建
rwd rw+同步文件内容的更新
rws rw+同步文件内容的更新和元数据的更新
*/
byte[] cbuf = new byte[1024];
int len;
while ((len = raf1.read(cbuf)) != -1) {
raf2.write(cbuf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
1
2
3
4
5
6
7
/*
abcdefg
0123456
*/
raf2.seek(3);
raf2.write("xyz".getBytes());
//efg变xyz

  断点续传。

NIO(New / Non-BlockingIO)

  从1.4开始,新的IOAPI。面向缓冲区的基于通道的IO操作。

  高效的文件读写。

  一套标准输入输出NIO,一套网络编程NIO。

  写得一般,所以在1.7出了NIO2。

java.nio.channels.Channel

  • FileChannel 处理本地文件
  • SocketChannel TCP网络编程的客户端的channel
  • ServerSocketChannel 网络编程的服务器的channel
  • DatagramChannel UDP网络编程的发送端和服务端的channel

Path、Paths、Files占位

  占位。有空仔细了解再写这里,因为当时刷,过去了,就展示了一些方法。

网络编程

  OSI(七层)参考模型过于理想化,未能在因特网上进行广泛推广。

TCP/IP 4层
应用层 HTTP、FTP、Telnet、DNS
传输层 TCP、UDP
网络层 IP、ICMP、ARP
物理+数据链路层 Link

  感觉我的三级网络技术还是有点用。

  InetAddress类代表IP。通过getByNamegetLocalHost得到实例。有至少两个方法getHostnamegetHostAddress

  0 ~ 1023:公认端口,1024 ~ 49151:注册端口,49152 ~ 65535:动态/私有端口。(为什么端口只有65535个,不告诉你。)

  UDP每个数据报的大小限制在64K内。无须释放资源,开销小,速度快。

  TCP的三次握手,四次挥手。虽然考过三级网络技术,做过相关的题,但感觉很难从口中说出。

自动关资源的try好呀
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
@Test
public void client() {
Socket socket = null;
BufferedOutputStream bos = null;
BufferedReader bf = null;
Scanner scanner;
try {
socket = new Socket("127.0.0.1", 8888);
bos = new BufferedOutputStream(socket.getOutputStream());
scanner = new Scanner(System.in);
bf = new BufferedReader(new InputStreamReader(socket.getInputStream()));

do {
bos.write((scanner.nextLine() + "\n").getBytes());
bos.flush();
System.out.println("转换为 " + bf.readLine());
} while (true);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bf != null) {
try {
bf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}


}

@Test
public void server() {
ServerSocket ss = null;
Socket socket = null;
BufferedReader br = null;
BufferedOutputStream bos = null;
try {
ss = new ServerSocket(8888);
socket = ss.accept();
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
bos = new BufferedOutputStream(socket.getOutputStream());

while (true) {
String s = br.readLine();
System.out.println("需要转换: " + s);
bos.write(s.toUpperCase().concat("\n").getBytes());
bos.flush();
System.out.println(233);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
if (br != null) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

}

  read是阻塞的方法,read相关的应该也是阻塞的。shutdownInput和shutDownOutput是不是过于粗暴了。文字相关的我是加的“\n”,来到达可以不停的发送和读。

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
public void sender(){
try (DatagramSocket datagramSocket = new DatagramSocket()) {
DatagramPacket datagramPacket = new DatagramPacket("ABC".getBytes(), 0, 3, InetAddress.getLocalHost(), 8888);
datagramSocket.send(datagramPacket);
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

@Test
public void receiver(){
try (DatagramSocket datagramSocket = new DatagramSocket(8888)) {
byte[] cbuf = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(cbuf, 0, cbuf.length);
datagramSocket.receive(datagramPacket);
System.out.println(new String(datagramPacket.getData()));
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

  先启动接收,在启动发送。

URL

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
InputStream is = null;
FileOutputStream fos = null;
try {
URL url = new URL("https://www.baidu.com/img/flexible/logo/pc/result.png");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
is = urlConnection.getInputStream();
fos = new FileOutputStream("src\\百度的图片.png");
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1){
fos.write(buffer, 0, len);
}
/*无异常*/
urlConnection.disconnect();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

  URL的常用方法:getProtocol协议、getHost主机名、getPort端口、getPath文件路径、getFile文件名、getQuery查询名。

反射 Reflection

  是视为动态语言的关键。Java是静态语言,可以视作准动态语言。

  静态语言:Java、C、C++。

  动态语言:Object-C、C#、js、PHP(最美的语言)、Python、Erlang。

  加载类后,堆内存的方法区就产生一个Class类型的对象。

能(运行时):

  • 判读任意一个对象所属的类。
  • 构造任意一个类的对象。
  • 判断任意一个类所具有的成员变量和方法。
  • 获取泛型信息。
  • 调用任意一个对象的成员变量和方法。
  • 处理注解。
  • 生成动态代理。

Class类的理解

  加载到内存的类,我们称为运行时类,此运行时类,就作为Class的一个实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Class<Persion> clazz = Persion.class;

Persion p = new Persion();
Class<Persion> clazz2 = p.getClass();

Class<Persion> clazz3 = Class.forName("Persion全类名");

clazz1 == clazz2;
clazz2 == clazz3;

ClassLoader cl = 当前类.class.getClassLoader();
Class<Persion> clazz4 = cl.loadClass("全类名");

clazz1 == clazz4;

  forName体现动态性。

Class类实例的对应结构

  Object.class 外部类,成员(成员内部类、静态内部类),局部内部类,匿名内部类。

  Comparable.class Interface。

  String[].class int[][].class []。

  ElementType.clas emun (target)。

  Override.class annotation。

  int.class primitive type 基本数据类型。

  void.class void

  Class.class

  []:元素类型与维度一样,就是同一个class。

(空参构造器为什么要写?方便框架反射造javabean,保证子类调super)

类加载

flowchart LR
subgraph a1[类的加载,load]
a12[class文件读入内存,创建class对象]
end
subgraph a2[类的链接,link]
a21[类的二进制数据合并到JRE中]

end
subgraph a3[类的初始化,initialize]
a31[JVM负责对类进行初始化]

end
a1-->a2
a2-->a3

加载:

  class文件加载到内存中并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象作为方法区中类数据的访问入口。所有需要访问和使用类数据只能通过这个class对象。这个加载过程需要类加载器参与。

链接:

  将java类的二进制代码合并到JVM的运行状态之中的过程。

  • 验证:确保加载的类信息符合JVM规范。例如:以cafe开头,没有安全方面的问题。
  • 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段。这些内存都将在方法区中进行分配。
  • 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。

初始化:

  • 执行类构造器<clinit>()方法的过程。执行类构造器<clinit>()方法是由编译期自动收集类中所有变量的赋值动作和静态代码中的语句合并产生的。
  • 当初始化一个类的时候,如果发现器父类还没有初始化,则需要先触发其父类的初始化。
  • 虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步。

ClassLoader

image-20210620161845947

  引导类加载器:C++编写。JVM自带加载器。负责Java平台核心库,用来装载核心类库。该加载器无法直接获取。

  扩展类加载器:负责jre/lib/ext目录下的jar包或-Djava.ext.dirs指定目录下的jar包载入工作库。

  系统类加载器:负责Java-classpath或-Djava.class.path所指的目录下的类与jar包装入工作,是最常用的类加载器。

1
2
3
4
5
6
7
Properties pros = new Properties();
//module下
//FIS fis = new FIS("jdbc.properties");
//module的src下
Inputstream is = 当前类.class.getClassLoader().getResourceAsStream("jdbc.properties");
pros.load(is);
pros.getProperty("user");

各种获取

创建运行时类的对象

要有空参构造器,权限得够。

1
2
Class<Person> clazz = Person.class;
Person obj = clazz.newInstance();

反射动态性体会

1
2
Class clazz = Class.forName("全类名");
return clazz.newInstance();

获取运行时类的属性结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Class clazz = Person.class;
//当前运行时类及其父类中声明为public的属性
Field[] fields = clazz.getFields();
//当前运行时类中声明的属性
Field[] declaredFields = clazz.getDeclaredFields();

Field f = declaredFields[0];
//权限
f.getModifier();//是int的、
Modifier.toString(f.getModifiers());
//类型
Class type = f.getType();
type.getName();
//变量名
f.getName();

获取运行时类的方法结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//当前运行时类及其父类中声明为public的方法
Method[] methods = clazz.getMethods();
//当前运行时类中声明的方法
Method[] DeclaredMethods = clazz.getDeclaredMethods();

Method m = DeclaredMethods[0];
//注解
Annotation[] annos = m.getAnnotations();
//权限
Modifier.toString(m.getModifiers);
//返回值
m.getReturnType.getName();//先返回一个class。
//方法名
m.getName();
//形参类型
class<?>[] parameters = m.getParameterTypes();
if(parameters != null && parameters.length != 0){
//处理,可以每一个getNmae.对于形参名,以前反射不可以,现在可以。不过可能需要在编译时添加一个参数
}
//异常类型
class<?> excptionTypes = m.getExcptionTypes();
//同上取一个处理。

获取运行时类的构造器

1
2
3
4
//当前运行时类(及其父类?忘了,测试没有)public的构造器
Constructor[] constructors = clazz.getConstructors();
//当前运行时类所有的构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();

获取运行时类的父类相关

父类

1
Class superClass = clazz.getSuperClass();

带泛型的父类

1
Type genericSuperclass = clazz.getGenericSuperclass();

带泛型父类的泛型

1
2
3
ParameterizedType paramType = (ParameterizedType) genericSuperclass;
Type[] actualTypeArguments = paramType.getActualTypeArguments();
System.out.println(actualTypeArguments[0].getTypeName());

  Type是接口,Class实现了Type,所以可以强转为Class再使用getName。

获取运行时类的接口

1
Class[] interfaces = clazz.getInterfaces();

  父类的接口可以先获取到父类,再获取接口

获取运行时类所在的包

1
Packge pack = clazz.getPackage();

获取运行时类的注解

1
Annotations[] annos = clazz.getAnnotations();

各种调用

调用指定属性

要求public

1
2
3
Field id = clazz.getField("id");
id.set(p,1001);
id.get(p);

常用的

1
2
3
4
Field name = clazz.getDeclaredField("name");
name.setAccessable(true);
name.set(p,"Tom");//p也可以是null
name.get(p);

调用指定方法

1
2
3
Method show = clazz.getDeclaredMethod("show",String.class);
show.setAccessible(true);
Object obj = show.invoke(p,"china");

调用静态方法

1
2
3
4
Method showDesc = clazz.getDeclaredmethod("showDesc");//无返回值。
showDesc.setAccessable(true);
Objiect rval = showDesc.invoke(Persion.class);
Objiect rval = showDesc.invoke(null);//本身clazz知道静态是啥(现在我无法准确理解,但在我笔记上就在这位置)

调用构造器

1
2
3
Constructor dcon = clazz。getDeclaredConstructor(String.class);
dcon.setAccessible(true);
Person person = dcon.newInstace("Tom");

动态代理

  Spring两大核心:IOC容器:常见方式依赖注入、AOP:原理:动态代理。

先来静态的。

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
 interface  ClothFactory{
void produceCloth();
}

Class ProxyClothFactory implements ClothFactory{
privite ClothFactory factory;
public ProxyClothFactory(ClothFactory factory){
this.factory = factory;
}
@override
public void produceCloth(){
syso("代理工厂做一些工作");
factory.produceCloth();
syso("代理工厂做后续工作");
}
}

Class NikeClothFactory implements ClothFactory{
@override
public void produceCloth(){
syso("Nike工厂生产运动服");
}
}

public static void main(String[] args){
ClothFactory nike = new NikeClothFactory();
ClothFactory proxyClothFactory = new ProxyClothFactory(nike);
proxyClothFactory.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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
interface Human{
String getBelief();
void eat(String food);
}

class SuperMan implements Human{
@Override
public String getBelief() {
return "I believe I can fly!";
}
@Override
public void eat(String food) {
System.out.println("我喜欢吃" + food);
}
}

class HumanUtil{
public void method1(){
System.out.println("====================通用方法一====================");

}
public void method2(){
System.out.println("====================通用方法二====================");
}
}
/*
要想实现动态代理,需要解决的问题?
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。
*/
class ProxyFactory{
//调用此方法,返回一个代理类的对象。解决问题一
public static Object getProxyInstance(Object obj){//obj:被代理类的对象
MyInvocationHandler handler = new MyInvocationHandler();

handler.bind(obj);

return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
}

}

class MyInvocationHandler implements InvocationHandler{
private Object obj;//需要使用被代理类的对象进行赋值
public void bind(Object obj){
this.obj = obj;
}
//当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()
//将被代理类要执行的方法a的功能就声明在invoke()中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
HumanUtil util = new HumanUtil();
util.method1();
//method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
//obj:被代理类的对象
Object returnValue = method.invoke(obj,args);
util.method2();
//上述方法的返回值就作为当前类中的invoke()的返回值。
return returnValue;

}
}

public class ProxyTest {
public static void main(String[] args) {
SuperMan superMan = new SuperMan();
//proxyInstance:代理类的对象
Object proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);//可以强转(可以泛型吗?)
Human proxyInstance = (Human)proxyInstance;
//当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
String belief = proxyInstance.getBelief();
System.out.println(belief);
proxyInstance.eat("四川麻辣烫");

System.out.println("*****************************");

NikeClothFactory nikeClothFactory = new NikeClothFactory();

ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);

proxyClothFactory.produceCloth();

}
}

AOP代理的方法

它在HumanUtil有体现。

1.0 1.2 1.5 1.7 1.8 1.10 1.11

  1.1的Calendar

  switch:5.0时的枚举,7.0时的String

  5.0可变参数。

  5.0自动装箱和 拆箱。

  5.0LocK锁

  5.0StringBuilder

  5.0注解

  5.0foreach

  5.0泛型

  8.0接口静态方法、默认方法

  8.0省略了方法的局部内部类关于变量的final的省略。

  8.0新的时间

  8.0两个新的注解特性

  8.0::

  我认为7891011有类型推断,只不过有些许差别。

8的其他特性

好处:

  1. 速度更快

  2. 代码更少

  3. 强大的StreamAPI

  4. 便于并行

  5. 最大画减少空指针异常

  6. Nashorn引擎,允许在JVM上运行JS应用

Lambda表达式

  Lambda是一个匿名函数,可理解为一段可以传递的代码。本质是函数式接口的实例。

例一

1
2
3
4
5
6
7
8
9
Runnable r1 = new Runnable(){
@Override
public void run(){
sout:我是sb
}
};
r1.run();
//重写
Runnable r2 = () -> sout:我是sb;

例二

1
2
3
4
5
6
7
8
9
Comparator<Integer> com1 = new Comparator<Integer>(){
@Override
public int compare(Integer o1, Integer O2){
return Integer.compare(o1,o2);
}
};
//重写
Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1,o2);
Comparator<Integer> com3 = Interger::compare;

格式

  左边:lambda形参列表(其实是接口中的形参列表)

  右边:lambda体(其实就是重写的抽象方法的方法体)

使用

  1. 无参,无返()->{语句}
  2. 一参,无返(String s) -> {语句}

谎言和誓言的区别是什么?

一个是听的人当真了,一个是说的当真了

  1. 类型推断Consumer<String> con = (s) -> {sout:s}
  2. 一参省括号,无返s - > {sout:s}
  3. 多参,多语句,可返(o1,o2) -> {sout:o1;sout:o2;return o1.compareTo(o2);}
  4. 只有一条语句(o1,o2) -> o1.compareTo(o2)

总结

  • 左边:参数类型可省略,只有一个参数的话,()也可省略
  • 右边:只有一条语句,{}可以省略,省略时,同时省略return

函数式接口(Funcational)

  接口中声明了一个抽象方法,称函数式接口。用FuncationalInterface注解,FuncationalInterface检验它是不是一个函数式接口。同时javadoc也会包含一条声明,说明这个接口是函数式接口。

  在java.util.funcation下定义了丰富的函数式接口。

四大内置核心函数式接口

四大内置核心函数式接口

其他接口

其他接口

方法引用

  也是函数式接口的实例。当要传递给lambda体的操作已经有实现的方法了,可以使用方法引用。要求实现接口的抽象方法的参数列表和返回值类型,必须和方法引用的方法的参数列表和返回值类型保持一致(主要针对情况1和2)。

使用格式:类或对象::方法名,具体三种情况:

  1. 对象::非静态方法
  2. 类::静态方法
  3. 类::非静态方法

构造器引用

  类::new

数组引用

  把数组看作特殊的类,则写法与构造器引用一致。String[]::new

强大的Stream API

  Stream APl(java.util.stream)把真正的函数式编程风格引入到Java中。这是目前为正对Java类库最好的补充,因为为sreamAPl可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

  Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行常复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简言之,Stream API提供了一种高效且易于使用的处理数据的方式。

  Stream和Collection集合的区别:Collection是一种静态的内存数据结构,而Stream是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。

注意

  1. Stream自己不会存储元素。
  2. Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。
  3. Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

创建:通过集合的方式

1
2
3
4
//default Stream<E> stream():返回一个顺序流
Stream<Employee> stream = employees.stream():
//default Stream<E> paralLelstream():返回一个并行流
Stream<Employee> parallelstream = employees.parallelstream():

创建:通过数组的方式

1
2
3
4
5
6
7
8
int arr =new int[]{1,2,3,4,5,6};
//调用Arrays类的static <T> Stream<T> stream(T[1 array): 返回一个流
IntStream stream = Arrays.stream(arr);

Employee e1 = new Employee(1001, "Tom");
Employee e2 = new Employee( 1002, "Jerry");
Employee[] arr1 = new Employee[]{el,e2};
Stream<Employee> streaml = Arrays.stream(arr1):

创建:通过Streamof()的方式

1
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);

创建:创建无限流

1
2
3
4
5
6
7
8
//送代
//public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
//遍历前10个偶数
Stream.iterate( 0, t -> t + 2).limit(10).forEach(System.out::println);

//生成
//public static<T> Stream<T> generate(Supplier<T> s)
Stream.generate(Math::random).limit(10).forEach(System.out::println);

中间操作——筛选与切片

  • filter(Predicate p):接收Lambda,从流中排除某些元素。
  • limit(n):截断流,使其元素不超过给定数量。
  • skip(n):跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补。
  • distinct():筛选,通过流所生成元素的hashcode()和equals()去除重复元素。

注:forEach()等终止操作会关闭流。报这个异常java.lang.IllegalstateException: stream has already been operated upon or closed

中间操作——映射

  • map(Function f):接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  • mapToDouble(ToDoubleFunction f):接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream。
  • mapTolnt(TolntFunction f):接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream。
  • mapToLong(ToLongFunction f):接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream
  • flatMap(Function f):接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。(相当于处理集合套集合)

中间操作——排序

  • sorted():产生一个新流,其中按自然顺序排序。
  • sorted(Comparator com):产生一个新流,其中按比较器顺序排序。

终止操作——匹配与查找

  • allMatch(Predicate p):检查是否匹配所有元素。
  • anyMatch(Predicate p):检查是否至少匹配一个元素。
  • noneMatch(Predicctep):检查是否没有匹配的元素。。
  • findFirst():返回第一个元素。
  • findAny():返回当前流中的任意元素。
  • count():返回流中元素的总个数。
  • max(Compargtor c):返回流中最大值。
  • min(Comparatorc):返回流中最小值。
  • forEach(Consumer c):内部送代。

终止操作——归约

  • reduce(T iden, BinaryOperator b):可以将流中元素反复结合起来,得到一个值。返回T。

  • reduce(BinaryOperator b):可以将流中元素反复结合起来,得到一个值。返回Optional<T>。

终止操作——收集

  collect(Collector c)将流转换为具他形式。接收一不Collector接口的实现,用于给Stream中元素做汇总的方法。另外,Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

方法 返回类型 作用
toList List<T> 把流中元素收集到List
List<Employee&qt; emps=list.stream().collect(Collectors.toList());
toSet Set<T&qt; 把流中元素收集到Set
Set<Employee> emps=list.stream().collect(Collectors.toSet());
toCollection Collection<T> 把流中元素收集到创建的集合
Collection<Employee> emps=list.stream().collect(Collectors.toCollection(ArrayList::new));
counting Long 计算流中元素的个数
long count=list.stream().collect(Collectors.counting());
summingInt Integer 对流中元素的整数属性求和
int total=list.stream().collect(Collectors.summingInt(Employee:getSalary));
averagingInt Double 计算流中元素Integer属性的平均值
double avg=list.stream().collect(Collectors.averagingInt(Employee:getSalary));
summarizingInt IntSummaryStatistics 收集流中Integer属性的统计值。如:平均值
int summaryStatisticsis = list.stream().collect(Collectors.summarizingInt(Employee::getSalary);
joining String 连接流中每个字符串
String str=list.stream().map(Employee::getName).collect(Collectors.joining());
maxBy Optional<T> 根据比较器选择最大值
Optional<Employee> max=list.stream().collect(Collectors.maxBy(comparingInt(Employee:getSalary)));
minBy Optional<T> 根据比较器选择最小值
Optional<Employee> max=list.stream().collect(Collectors.minBy(comparingInt(Employee:getSalary)));
reducing 归约产生的类型 从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值
int total=list.stream().collect(Collectors.reducing(0,Employee::getSalar, Integer:sum));
collectingAndThen 转换函数返回的类型 包裹另一一个收集器,对其结果转换函数
int how=list.stream().collect(Collectors.collectingAndThen(Collectors.toList(),List::size))
groupingBy Map<K, List<T>> 根据某属性值对流分组,属性为K,结果为V
Map<Employee.Status,List<Employee>> map=list.stream().collect(Collectors.groupingBy(mployee::getStatus));
partitioningBy Map<Boolean, List<T>> 根据true或false进行分区
Map<Boolean,List<Employee>> vd=list.stream().collect(Collectors.partitioningBy(mployee::getManage)));

Optional类

  Optional<T>类(java.util.Optional)是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

Optional<T>

9的新的特性(我不喜欢的提供链接自己看

10的新特性

  var和集合的copyOf方法,其他的就不管了。

11的新特性

  • String的新增的方法:isBlank()strip()去除首尾空白、" Javastack ".stripTrailing();去除尾部空白、" Javastack ".stripLeading();去除首部空白、"Java".repeat(3);//"JavaJavaJava"复制字符串、"A\nB\nC".lines().count();行数统计

  • Optional的isEmpty()

  • (@Deprecated var t) -> System.out.println(t.toupperCase());局部变量类型推断的升级

  • 全新的HTTP客户端API

    1
    2
    3
    4
    5
    6
    HttpClient client =HttpClient.newHttpClient();
    HttpRequest request = HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test/")).build();
    BodyHandler<String> responseBodyHandler = BodyHandlers.ofstring();
    HttpResponse<string> response = client.send(request, responseBodyHandler);
    String body = response.body();
    System.out.println(body)
    1
    2
    3
    4
    5
    6
    7
    8
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request =HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test/")).build);
    BodyHandler<String> responseBodyHandler= BodyHandlers.ofString();
    CompletableFuture<HttpResponse<String>> sendAsync = client.sendAsync(request,responseBodyHandler);
    sendAsync.thenApply(t->t.body()).thenAccept(System.out::println);
    //HttpResponse<String>response= sendAsync.get();
    //string body=response.body();
    //System.out.println(body);
  • 更简化的编译运行程序:java Test.java

    • 执行源文件中的第一个类,第一个类必须包含主方法。
    • 并且不可以使用其他源文件中的自定义类,本文件中的自定文类是可以使用的。
  • 废弃Nashorn引擎,需要的话,可以考虑GraaIVM

  • ZGC是一个并发,基于region,压缩型的垃圾收集器,只有root扫描阶段会STW(stop the world),因此GC停顿时间不会随着堆的增长和存活对象的增长而变长。

    • GC暂停时间不会超过10mS
    • 既能处理几百兆的小堆,也能处理几个T的大堆(OMG)
    • 和G1相比,应用吞吐能力不会下降超过15%
    • 为未来的GC功能和利用colord指针以及Load barriers优化奠定基础
    • 初始只支持64位系统
  • Unicode10

  • Deprecate the Pack200 Tools and APl

  • 新的Epsilon垃圾收集器

  • 完全支持Linux容器(包括Docker)

  • 支持G1上的并行完全垃圾收集

  • 最新的HTTPS安全协议TLS1.3

  • JavaFlightRecorder

到17的新特性

  • 在14之前,进行类型转换的时候,最好进行instanceof判断,再进行转换。

    之后可以这样:

    1
    2
    3
    4
    5
    6
    Object obj =new String("hello,Java14");
    if(obj instanceof string str){
    System.out.println(str.contains("Java"));
    }else{
    System.out.println("非string类型");
    }
     14引入预览,15二次预览,16转正,可以放心使用了。
    
  • switch表达式,12预览,13二次预览,14转正。12中引入case L ->来替代break,用变量接收结果~~(必须有default)~~。13引入yield,用于返回指定的数据,结束switch结构。switch表达式(返回值)应该使用yield,switch语句(不返回值)应该便用break

  • switch的模式匹配,17预览。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    String formatted = switch(o){
    case Integer i:
    yield "int " + i;
    case Long l:
    yield "long " + l;
    case Double d:
    yield "double " + d;
    case String s:
    yield "String " + s;
    default:
    yield o.toString();
    };
  • 文本块,13预览,14二次预览,15转正。 14加入\取消换行,\s表示空格。

    1
    2
    3
    “”“
    各种字符串
    “”“
  • record的使用。实现一个简单的数据载体类,为了避免编写:构造函数,访可器,equals()hashCode()toString()等,Java14推出record。record是一种全新的类型,它本质上是一个final类,同时所有的属性都是final修饰,它会自动编译出public gethashcodeequalstoString、构造器等结构,减少了代码编写量。

  • 密封类。在Java中如果想让一个类不能被继谜承和修改,这时我们应该使用fina1关键字对类进行修饰。不过这种要么可
    以继承,要么不能继承的机制不够灵活,有些时候我们可能想让某个类可以被某些类型继承,但是不能随意继
    承,是做不到的。Java15尝试解决这个问题,引入了sealed类,被sealed修饰的类可以指定子类。这样这
    个类就只能被指定的类继承。15预览,16二次预览,17转正。 //子类要为finalsealednon-sealed(无限制)

    1
    2
    public sealed class Person permits Student,Teacher,Worker{
    }
  • 12中,String实现Constable接口,新增transform(Function)方法。17中,标记删除Applet API(9标记过时)。9之后,不允许使用_作为变量。

  • 9以后,默认G1 GC;10为G1提供并行的Full GC;12可中断的G1 Mixed GC,增强G1,自动返回未用堆内存给操作系统;~~Shenandoah GC:低停顿时间的GC;15shenandoah垃圾回收算法转正;~~11 引入革命性的 ZGC;12ZGC功能转正;16ZGC并发线程处理

其他

这个输入皮肤挺好看的。

输入法皮肤.PNG