万字总结javase

目录

第一章

第二章

第三章

数组

JAVA内存分配

第四章

第五章



JAVA基础知识全面复习

第一章

编写代码、编译代码、运行代码

class :定义一个类 ,后面跟上helloworld

程序执行时的入口点,main方法也是主方法

踩坑:

运行JAVA程序后出现找不到或无法加载主类

经排查发现是权限不够 ,以管理员身份运行JAVA程序

常见面试题:

JDK、JVM、JRE的区别

1.JVM:java虚拟机,真正JAVA程序运行的地方

JRE:JAVA运行环境 JRE 包括 JVM+核心类库 核心类库:JAVA自己写好的程序

JDK:JAVA开发工具包(包括上面所有) JRE+开发工具

PATH环境变量:记住程序路径

JAVA_HOME:告诉操作系统JDK安装在了那个位置

IDEA基本结构

Project-module-package-class

快捷键

JAVA基本语法

变量:内存中的一块区域用来存储数据,并且数据可以改变 变量要先申明后使用,申明后不可以更改数据 不可重名 定义可以不初始化 使用必须初始化

关键字:JAVA语言自己用到的一些字 ;类名或者变量名称时,不能使用这些词

标识符:方法名、变量名、类名 基本要求:由数字、字母、下划线、$组成

不能以数字开头、不能是关键字、区分大小写

变量名称:全英文 首字母小写 驼峰命名

类名称:首字母大写 驼峰命名

第二章

数据类型是约束变量存储数据的形式

基本数据类型:

整数 byte short int(默认) long

浮点数 float double (默认)

字符 char

布尔 boolean

引用数据类型

自动类型转化 小——大

强制类型转化 大-------小 类型范围大的数据不能直接赋值给类型范围小的数据

注意事项: 强制类型转换可能造成数据溢出

浮点型 强转成整形 直接截断小数

运算符:算术运算符、自增自减运算符、赋值运算符、关系运算符、逻辑运算符、三元运算符、运算符优先级

算术运算符:+ - * / %

+做连接符: 能算则算,不能算就在一起

自增自减运算符

++前:先运算再使用 ++后: 先使用后运算

赋值运算符: =、+=、-=、*=、/=、%=

关系运算符:==、!=、>、>=、<、<=

逻辑运算符:&、|、! ^(异或)

短路与 && ||

三元运算符: 条件表达式 ?值1:值2

运算符:*/高于+-

程序控制:顺序结构(程序默认流程)、分支结构(判断条件选择程序执行)、循环结构(重复执行某段程序)

分支结构:if switch

switch: 表达式只能是byte short int char String 不支持 double float long

case给出的值不允许重复,并且只能是字面量、不能是变量

不要忘记写break 否则会出现穿透

三种循环的区别 for循环和while循环 (先判断后执行)

do ....while(先执行后判断)

break :跳出并结束当前所在循环

continue:跳出当前循环

Random

作用:用于在程序中获取随机数的技术

nextInt(n):生成0~n-1的随机数,不包含n

第三章

数组

数组就是用于存储一批同种类型数据的容器

静态初始化数组:

数据类型[] 数据名 ={元素1,元素2,元素3........}

数组是引用类型,数据变量名是存储在内存中的地址

数组中的动态初始化

int [] arry=new int[3]; 确定长度

区别:当前已经知道存入的元素值.用静态初始化

当前不知道数据.用动态初始化 不可以混用

JAVA内存分配

栈、推、方法区、本地方法栈、寄存器

方法区:字节码文件加载时进入内存

栈内存:方法运行时所进入的内存 变量就在这里

堆内存:new 出来的东西会在这块内存中开辟空间并产生地址

基本类型变量 存储的时变量本身 引用数据类型 存储的时所指向的地址

超过最大索引 ArrayIndexOutofBoundsException

数据变量中没有存储数组的地址 访问数组信息NULLPointerException

第四章

方法

方法修饰符 返回值类型 方法名称 形参列表

public static add (int a,int b)

方法的内存图

方法没有被体哦啊用的时候 ,在方法区中的字节码文件中存放

方法被调用 .需要在栈内存中运行

方法的参数传递机制:

在传输实参给方法形参时,并不是传输实参变量本身 ,而是传输实参变量中存储的值,这就是值传递

形参:以方法为例 就是方法定义时的变量

实参:在方法内部定义的变量

值传递:传输的是实参存储的值

基本类型和引用类型的参数在传递的时候的区别

都是值传递

基本类型的参数传输存储的是数据值

引用类型的参数传输存储的地址值

方法的重载与重写:

重载:同一个类中,出现多个方法名称相同 ,但是形参列表不同,那么这些方法是重载方法(忽视修饰符、返回值类型)

方法的重写:子类对父类的允许访问的方法的实现过程进行重新编写

双色球案例

注意:随机生成中奖号码时应该时每个红球号码都不重复

OOP

对象在内存中的运行机制

栈内存: Car c1放置引用变量地址 堆内存: new 出来的对象 放置对象成员方法的引用地址

调用方法的过程:

1、c1所指向的对象

2、方法的引用找到start方法

3、在推内存中运行start方法

垃圾回收

垃圾对象:堆内存的对象无任何引用指向该对象 定期回收

构造器: 定义在类中,可以初始化一个类的对象,并返回对象的地址

无参、有参

this:

可以出现在构造器、方法中 代表当前对象的地址

封装:

如何正确设计对象的属性和方法

面向对象的三大特征:封装、继承、多态

一般建议把成员变量使用 private隐藏起来,不对外访问

提供public修饰的getter和setter方法暴露其取值和赋值

javaBean:实体类,其对象可以用于在程序中封装数据

成员变量和局部变量的区别:

区别 成员变量 局部变量

类中的位置 类中方法外 方法内

初始化值 有默认值 无默认值

内存位置 堆 栈

生命周期 随对象 随方法

作用域 所属大括号

常见API

String和ArrayList

String类定义的变量可以用于指向字符串对象 然后操作字符串 不可变字符串类型 对象在创建后不可以修改

字符串对象在字符串的常量池中

只是引用变量指向新的对象的地址

equals方法默认==字符串中重写该方法 只关心内容是否一致

常见 API

length()、charAt 、toCharArray、substring replace

eg: String s1=new String ("abc"); 两个对象

String s2="abc";0个对象

s1==s2 false

eg: 只要不是双引号直接给出不放到字符串常量池

eg: String s1="abc"

String s2="a"+"b"+"c"

s1==s2 true 字符串常量池的数据共享

编译优化机制,在编译自动转成 abc

ArrayList集合

常见 API

add 泛型:只支持引用类型 编译阶段约束集合对象只能操作某种数据类型

get size remove set修改指定位置的元素

集合中存储的时堆内存的地址

第五章

static关键字: 设计模式:单例模式:有些类只需要一个对象就可以了,如何实现一个类只能对外产生一个对象

static静态:可以修饰成员变量、成员方法

static修饰成员变量之后称为静态成员变量(类变量),修饰方法之后称为静态方法(类方法)

static修饰后的成员变量,可以被类的所有对象共享(访问、修饰)

成员变量内存原理

static:静态的意思,可以修饰成员变量、成员方法 静态成员变量(static修饰,属于类、加载一次,内存中只有一份)

实例成员变量(无static修饰,属于对象)

两种成员变量:静态成员变量:表示在线人数等需要被类的所有对象共享的的信息

实例成员变量;属于每个对象,且每个对象的该信息不同

静态成员方法:(有static修饰,归属于类):建议用类名访问,也可以用对象访问

实例成员方法:(无static修饰,归属于对象) 只有对象触发访问

静态成员方法(有static修饰,属于对象和类共享):类名。静态成员方法 对象.静态成员方法

实例成员方法:(无static修饰,属于对象) 对象.实例方法

static注意事项:

静态方法只能访问静态成员,不可以直接访问实例成员

实例方法可以访问静态成员,也可以访问实例成员

静态方法是不可以用this关键字

工具类:工具里面都是静态方法,直接类名即可访问 工具类无需创建对象 ,建议将工具类的构造器进行私有

代码块:类中的五大成分(成员变量、构造器、方法、代码块、内部类)

静态代码块:初始化静态资源

设计模式

开发中经常遇到一些问题 ,一个问题通常有n种揭解法,但其中肯定有一种解法最优 ,称为设计模式

单例模式 应用该模式的这个类永远只有一个实例,即一个类永远只能创建一个对象

饿汉单例 : 在用类获取对象的时候,对象已经提前为你创建好了

懒汉单例: 在真正需要该对象的时候,才去创建对象(延迟加载对象)

//1.定义一个类,把构造器私有 定义一个静态变量存储一个对象 提供一个返回单例对象的方法

继承

继承就是JAVA运行我们用extends 关键字 让一个类和另外一个类建立父子关系

提高代码的复用性 减少代码冗余

父类:共性 子类:特有

内存空间中

子类空间:

父类空间:

子类可以继承父类的属性和行为,但是子类不能继承父类的构造器

JAVA是单继承模式,一个类只能继承一个直接父类 JAVA不支持多继承 JAVA中所有的类都是Object类的子类

子类方法中访问成员:就近原则,子类没有找子类 子类没有找父类 父类没有保错

出现重名:super.父类成员变量 私有方法不能被重写 子类重写父类方法时,访问权限大于或等于父类被重写的权限

子类初始化,一定

子类构造器中:默认第一行语句:super() 不写也存在

子类中所有构造器默认都是先访问父类中无参的构造器,再执行自己

this和super使用的注意点

子类通过 this(...)去调用本类的其他构造器 ,本类其他构造器会通过super去手动调用父类构造器

this(...) super(...)都只能放在构造器的第一行 所以二者不能存在同一个构造器

包: 修饰符 同一个类 同一个包中的其他类 不同包下的子类 不同包下的无关类

private √

default √ √

protected√ √ √

public √ √ √ √

final关键字:final关键字时最终的意思 可以修饰(类、方法、变量)

修饰类:表明该类是最终类 不能被继承

修饰方法: 表明该方法是最终方法 不能被重写

修饰变量:表示该变量第一次赋值后,不能再次被赋值(有且仅能被赋值一次)


final 注意:final修饰的变量是基本类型:变量存储的数据值不能发生改变 final修饰的变量是引用类型:变量存储的地址值不能发生改变,但是地址指向的对象内容是可以发生改变

public static final修饰的成员变量 必须有初始值,而且执行的过程不能改变

枚举是JAVA中的一种特殊类型 枚举的作用:为了做信息的标志和信息的分类

抽象类:

抽象方法中只有方法签名,不能声明方法体

一个类如果定义了抽象方法,这个类必须声明成抽象类

抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类

abstract:得到了抽象方法,不能创建对象

多态

多态:指对象可以有多种形态

前提:有继承关系 父类引用指向子类对象 方法重写

自动转化 子到父 强制转化 父到子 instanceof(判断当前对象的真实类型)

接口:

类和类的关系:单继承

类和接口的关系:多实现

接口和接口的关系:多继承,一个接口可以同时继承多个接口

JDK8开始新增的方法

默认方法:默认会public修饰。需要用接口的实现类的对象来调用

静态方法:static修饰,必须用当前接口名调用

私有方法:private修饰 ,jdk9开始只能在接口内部被调用

默认public

内部类:定义在一个类里面,里面的类可以理解成寄生,外部类可以理解成宿主

访问外部内对象 外部类名.this

匿名内部类

本质上是一个没有名字的局部内部类 作用:方便创建子类对象 最终目的是为了简化 编写

特点总结:匿名内部类是一个没有名字的内部类,同时也代表一个对象

匿名内部类产生的对象类型,相当于是当前new的那个的类型的子类类型

Object的equals方法: equals方法默认是比较当前对象与另外一个对象的地址是否相同,相同返回true 不同 false

Objects类的toString equals方法

StringBuilder的核心作用:操作字符串的性能比string要更高

stringBuilder:内容是可变的、拼接字符串性能好、

String:内容不可变 拼接字符串性能差

BigDecimal

Date 类: Date类代表当前所在系统的日期时间信息

日期对象创建: public Date(); public long getTime();

恢复时间: public Date(long time); public void setTime(long time);

简化日期格式化:SimpleDateFormat 构造器 public SimpleDateFormat(String pattern) 创建简单日期格式化对象

格式化方法 format(Date date) 将日期格式化成日期 format(Object time)将时间毫秒值化成日期

parse(String source):解析字符串时间

新的日期API

localDate:不包含具体时间的日期 LocalTIme:不包含日期的时间

LocalDateTIme:包含了日期及时间

Instant 代表时间戳

Arrays类:数组操作工具类

toString(类型 [] a) 返回数组的内容

Comparator 重写 compare方

Lambda表达式只是简化函数式接口的匿名内部类的写法形式

函数接口中有@FunctionallInterdface

Lambda表达式的规则: 参数类型可以不写

如果只有一个参数 ()也可以省

lambda 只有一行 可以省 大括号 省分号 若是return语句 必须省return 同时也必须省;

集合{

Collection:单列

Map :双列

}

Collection集合

迭代器: Iterator

lists.foreach 结合lambda表达式

数据结构 栈、队列、数组、链表、二叉树、二叉查找树、平衡二叉树、红黑树

二叉树:父节点、值、左子节点地址、右子节点地址

只有一个根节点:

节点的度节点拥有的子树的个数 高度:叶子节点为1 层:根节点y在第一层 兄弟节点:有公共父节点的节点叫叶子节点

二叉查找树 :

平衡二叉树:满足二叉查找树的基础上数据分布均匀 提高二叉树数据的性能**

任意节点的左右两个子树的高度差不超过1,任意节点的左右两个子树是一颗平衡二叉树

平衡二叉树:左旋、右旋 左左 右旋 左右1.先左旋 成左左再右旋 右右 往左啦 右左 先右拉再左拉 (左子树 的左节点 左子树的右节点 )

TODO 红黑树:平衡二叉B树 平衡二叉查找树

ArrayList底层原理:ArrayList底层是基于数组实现的,根据索引定位元素快 增删需要左元素移位操作

默认为10

LinkedList 底层数据结构是双链表,查询慢 ,首尾操作极快,

stream流

异常:Throwable

error exception

RuntimeException 除RuntimeException之外的异常

常见的异常:

数组索引越界异常:ArrayIndexOutOfBoundsException

空指针异常: NullPointerException

数学操作异常:ArithmeticException

类型转换异常: ClassCastException

数字转换异常 NumberFormatException

编译时异常的处理形式:出现 异常直接抛出去给调用者 ,调用者也继续抛出去

出现异常自己捕获处理,不麻烦别人

异常的默认处理机制:默认会在出现异常的代码的创建一给异常对象

异常会从方法出现的点这里直接抛出给调用者 调用者最终抛给JVM虚拟机

虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据

直接从当前执行的异常点干掉程序

后续代码无机会执行

  • throw 在方法体内使用,throws 函数名后或者参数列表后方法体前

  • 意义 : throw 强调动作,而throws 表示一种倾向、可能但不一定实际发生

  • throws 后面跟的是异常类,可以一个,可以多个,多个用逗号隔开。throw 后跟的是异常对象。

img

自定义异常

//自定义异常

1.自定义异常类,继承Exception

2、自定义构造方法,无参、带参都可 传入异常信息

3、上抛 throws异常

异常是一个非常好用的工具,可以在不中断程序的同时发现问题,所以这个方法一定要掌握 异常分运行时异常和编译时异常,要知道如何区分,编译时异常在写代码的时候编译器就会报错,运行时异常在程序运行时才会报错 throws 抛异常,抛得最远只能到main方法, 如果再继续抛,到jvm虚拟机,它不会处理异常,会报错 手写异常,一般都要把异常抛出去,不然自己写的异常马上又处理 了,没有意义 try catch 是直接把异常处理掉了,throws 是向上抛异常,也是一种异常的处理方式throws 抛异常,抛得最远只能到main方法, 如果再继续抛,到jvm虚拟机,它不会处理异常,会报错 手写异常,一般都要把异常抛出去,不然自己写的异常马上又处理 了,没有意义 try catch 是直接把异常处理掉了,throws 是向上抛异常,也是一种异常的处理方式

**throw 用于抛出一个已知的异常,而 throws 用于声明可能会抛出的异常。**

throws: 可以跟多个异常类名,用逗号隔开 throw: 只能抛出一个异常对象名

throws:
     表示抛出异常,由该方法的调用者来处理
 
 throw:
    表示抛出异常,由该方法体内的语句来处理

throws: throws表示有出现异常的可能性,并不一定出现这些异常 throw: throw则是抛出了异常,执行throw一定出现了某种异常

使用 throw 时,必须指定异常对象

设计模式 工厂设计模式 提供获取对象的方式

装饰模式:在不改变原来基础上动态增加功能

线程池的三种方式的对比:

继承Thread类

实现 Runnable接口 实现Callable接口

TODO IO流 多线程 红黑树

FILE类和IO流

数据希望以文件的形式存储 1、围绕文件的操作 2、读写数据

File类的对象代表操作系统中的文件、文件夹 File类提供了诸如:创建文件对象代表文件、获取文件信息(大小、修改时间) 删除文件、创建文件

pathname String 绝对路径是带盘符 相对路径不带盘符

常见方法:isDirectory() isFile() exists () length() getAbsolutePath() getPath() getName() lastModified()

创建文件、删除文件; createNewFile mkdir mkdirs delete

listFiles() 获取当前目录下所有的“一级文件对象”到文件对象数组中去返回

注:listFiles只能返回一级文件对象

delete方法默认只能删除文件和空文件夹 ,delete直接删除不走回收站

递归算法的三要素

递归公式:f(n)=f(n-1)*n 递归的终结点 f(1) 递归的方向走向终结点

文件搜索:先定位出的是一级文件对象 遍历全部的以及我文件对象 判断是否是文件 如果是文件 判断是否是自己想要的 如果是文件夹继续递归

字符集: ASCII:包含数字、英文、符号

GBK:包含了几万个汉字等字符

英文和数字等在任何国家的字符集都占1个字节 GBK字符中一个中文字符占2个字节 UTF-8中一个中文占3个字节

字符集编码和解码需要一致,否则会乱码

字符集的编码、解码操作

String编码; getBytes() getBytes(String charsetName):指定编码 解码 String(byte[] bytes ,String charsetName)

IO流: I表示input,输入的过程,负责读 O表示output 把内存的数据写出到硬盘文件的过程,称为输出,负责写

IO流:按流中的数据最小单位分为字节流、字符流

操作所有类型的文件、只能操作纯文本文件、


字符流:Reader Writer FileReader FileWriter

字节流:inputStream OutputStream FileInputStream FileOutPutStream

FileInputStream fileInputStream=new FileInputStream(file);
System.out.println(fileInputStream.read());

以字节的形式进行读取 每次读取第一字节 字节数组

定义一个字节数组与文件的大小一样大 一次性读取完成 字节输入流InputStream

FileOutputStream:以内存为基准 ,把内存中的数据以字节的形式写到磁盘文件中的流

flush():刷新流,还可以继续写数据 close():关闭流,释放资源

字符流:字符流-一次读取一个字符 字符输入流-依次读取一个字符数组 字符输出流

字节缓冲输入流自带了8KB缓冲流,以后直接从缓冲池中读取数据

缓冲流自带缓冲区 :缓冲流也称为高效流 作用:缓冲流

缓冲流自带缓冲区,可以提高原始字节流、字节流读写数据的性能

字节缓冲流输入流:BufferedInputStream BufferedOutputStream 字符缓冲输入流:BufferedReader BufferedWriter

转换流:InputStreamReader OutputStreamWrite将字节流转换为字符流

对象序列化:以内存为基准,把内存中的对象存储到磁盘文件中去,称为对象序列化 使用的流是对象字节输出流 ObjectOutputStream 把低级字节输出流包装成高级的对象字节输出流 ObjectOutputStream把对象写出去到对象序列化流的文件中去

注:JAVA对象序列化乱码正常,(若不想为乱码)需要自己实现序列化

PrintStream PrintWriter

l打印数据功能上是一模一样的,都是使用方便,性能高效(核心优势)

lPrintStream继承自字节输出流OutputStream,支持写字节数据的方法。

lPrintWriter继承自字符输出流Writer,支持写字符数据出去。

打印流一般是指:PrintStream PrintWriter

PrintStream继承自字节输出流OutputStream PrintWrite 继承字符输出流Writer

第五章

多线程

多线程的创建的三种方法:

继承Thread类,重写run()方法

只有调用start方法才是启动一个新的线程

方法一:1.继承Thread类 2.重写run 3.创建线程对象 4.调用start方法

方法二:1.实现Runable接口 ,重写run()方法 2.创建MyRunnable对象 3.将MyRunnable对象交给Thread类处理 4.调用thread类的start()

方案二.2:可以创建Runnable接口

方案三:利用Callable、FutureTask接口实现

1.创建类实现Callable接口

2.创建线程任务对象 FutureTask把Callable对象封装成线程对象

3.创建thread类接受线程任务对象

4.调用start方法 利用futureTask放回结果

Thread getName()获取当前线程名称 setName 设置线程名称 currentThread返回当前正在执行的线程对象的引用 run 线程任务方法 start 线程启动方法

线程安全问题发生的原因:多个线程同时访问同一个共享资源并且存在修改该资源

解决方法同步代码块: synchroized

作用:把发现线程安全问题的核心代码给上锁 原理:每次只能一个线程进入,执行完毕解锁

同步方法:把出现线程安全的核心方法给上锁 synchronized

ctrl+alt+t键快捷键

锁对象任意的唯一:不好,影响其他线程的执行

规范:建议使用共享资源作为锁对象 对于实例方法建议使用this作为锁对象 静态方法建议使用 字节码.class

同步方法: syschronized 层可瑞子的

同步方法其实底层也是隐式锁对象

Lock锁 罗格锁

Lock上锁和解锁更加灵活 :Lock接口 ReentrantLock来构建Lock锁对象

Lock的API ReenttrantLock 瑞吹歌罗格

线程池

线程池就是一个可以复用线程的技术

如果用户发送一个请求 后台就创建一个线程来处理,下次新任务来了又要创建新线程 ,而创建新线程的开销比较大

工作线程:WorkThread WorkQueue

代表线程池的接口:ExcutorService e可四service Tool

两种: ExecutorService ThreadPoolExecutor EXecutors(线程池的工具类)

corePoolSize maximumPool keepAliveTime unit workQueue threadFactory handler

指定线程池的线程数量 指定线程池可支持的最大线程数 指定线程池的最大存活时间 指定存活时间的最大

临时线程什么时候创建:核心线程都在忙 任务队列满 并且还可以创建临时线程 创建临时线程

pool shutdownNow()立即关闭 即使任务没有完成,会掉任务 shutdown()热舞执行完成后关闭

Runnable对象 Callable对象 submit提交

Excutors得到线程类的工具类通过调用方法返回不用类型的线程类对象

newCachedThreadPool() newFixedThreadPool

ExecutorService newFixedThreadPool(int nThreads)

定时器:

方式一:Timer 方式二:ScheduledExecutorService s可to的

定时器是一种控制任务延时调用,或者周期调用的技术

线程的六种状态

网络编程关键三要素:IP地址、端口、协议

IPV4(32bit)四字节 IPV6(128bit)16个字节 IPV6分成8个整数,每个整数用四个16进制表示 数之间用:分开

IP地址形式: 公网地址和私有地址

InetAddress: getLocalHost(获取当地) getByName getHostName getHostAddress isReachable(IP地址是否互通)

192.168开头的就是常用的局域网地址,范围为192.168.0.0-192.168.255.255 专门为组织机构内部使用

端口号:标识正在计算机设备上运行的进程,被规定为一个16位的二进制

端口类型:周知端口(0-1023)被某些知名应用占用、、 注册端口(1024-49151) 动态端口(49152-65535)

传输层的2个常见协议:传输控制协议 用户数据报协议 TCP协议特点:

TCP协议,必须双方先建立连接 它是一种面向连接的可靠通信的协议 传输前 采用 三次握手的方式建立连接,所以是可靠的 在连接中可进行大数据量的传输 来凝结、发送数据都需要确认,且传输完毕后,还需是释放已建立的连接

TCP三次握手、四次挥手:

三次握手: 客服端向服务器发出请求 服务器给客服端返回响应信息、客服端再次发出确认请求

四次挥手:客服端向服务器发出取消请求的连接 、服务器向客服端发出一个响应、服务器向客服端发出确认取消信息、客服端再次发送确认信息

UDP协议:UDP是一种无连接、不可靠传输的协议 UDP协议通信场景:语音通话、视屏会议

UDP通信实现:发送消息、接受消息 1.创建DatagramSocket(data歌瑞缩雷特)对象(发送端对象) DatagramPacket对象封装需要发送的数据 使用DatagramSocket对象的send方法传入DatagramPacket对象

UDP快速入门; 发送端:DatagramSocket(人) DagegramPacket()韭菜盘子 里面装有数据 指定服务器端的端口号 人发送韭菜盘子中的数据

接受端: DatagramSocket(人)指定服务器端端口号 创建韭菜盘子 接受数据 打印数据

send发送端的数据 receive接受数据

UDP的三种通信方式: 单播:单台主机与单台主机之间的通信

广播 :当前主句与所在网络中的所有主机的通信 组播:当前主机与选定的一组主机的通信

使用广播地址:255.255.255.255

DatagramSocketd的子类 MulticastSocket可以在接收端绑定组播IP

TCP通信模式

TCP是一种面向连接、安全、可靠传输数据的协议 传输前.采用“三次握手”方式,点对点通信,是可靠的

传输前,采用“三次握手”方式,点对点通信,是可靠的

在连接中可进行大数据量的传输

TCP多发多收 不可以接受多个客服端的消息

TCP可以处理多个客服端的通信

引入多线程、

线程池:服务端可以复用处理多个客户端 可以避免系统崩溃

//线程池 工作线程 最大线程 任务队列

线程池的优势:服务端可以复用线程处理多个客服端 适合客户端同行时长较短的场景

即使通信 点对点 ,一个客户端的消息 另外一个客户端接受

即使通信:端口转发

BS结构:socket

Junit框架

单元测试

怎样进行预期结果的正确性测试:断言 assertEquals 返回值

@Before @after @BeforeClass 修饰静态方法

反射

反射是指对于任何一个class类 在运行的时候都可以直接得到这个类的全部成分

这种运行时动态获取类信息以及动态调用类中的

得到这个类的构造器对象 Constructor Field Method class类对象

反射是在运行时获取类的字节码文件对象

class作为一个类型

得到Class类的方法 Class类的forName

类名.class

对象.getClass();

反射:第一步获得 class对象 获得Constructor对象 创建对象

getConstructor getDeclaredConstructor(无所谓权限)

使用反射技术获取构造器对象并使用 newInstance() 根据指定的构造器创建对象

暴力反射 setAccessible 权限被全开 反射破坏封装性

利用反射技术获取构造器对象的方式 : getDelaredConstructors()

反射获取成员变量

Filed类 set get

getDeclaredMethod:获取方法的执行的参数

Method类用于触发执行的方法 invoke(对象) 返回结果回来 那么返回的是null 关系反转

反射是作用在运行时的技术,此时集合的泛型将不能产生约束 此时可以为集合存入其他任意类型的元素的

反射可以绕过编译阶段

反射做通用框架:

注解的作用:对JAVA中类、方法、成员变量做标记,然后进行特殊处理

只有单个value可以不写

元注解: 注解的注解 @Target:约束自定义注解只能在哪些地方使用 @Retention:申明注解的生命周期

注解解析

Annotation

工厂模式:对象通过工厂的方法创建返回,工厂的方法可以为该对象进行加工和数据注入

可以实现类与类的解耦

装饰模式:在不改变原有的类的功能形况下对类的功能进行增强

动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术

根据我们在动态代理对象中的“指示”,动态生成的。也就是说,你想获取哪个对象的代理,动态代理就会为你动态的生成这个对象的代理对象

  • 首先由Proxy类的静态方法newProxyInstance创建动态代理对象

  • public static Object newProxyInstance

  • (ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

  • 而要创建该对象,需要3个参数

  • ClassLoader loader:定义了由哪个ClassLoader对象来对生成的代理对象进行加载

  • Class<?>[] interfaces:表示的是我将要给我需要代理的对象提供一组什么接口

  • InvocationHandler h:既然一个指明了加载器,一个指明了接口,那么这个就是具体实现功能的方法了。

  • InvocationHandler h:既然一个指明了加载器,一个指明了接口,那么这个就是具体实现功能的方法了。

  • InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

  • 每一个动态代理类都必须要实现InvocationHandler这个接口,当我们通过代理对象调用一个方法的时候,

  • 这个方法的调用就会被转发为由InvocationHandler这个接口的invoke 方法来进行调用

  • public Object invoke(Object proxy, Method method, Object[] args)

  • InvocationHandler接口中invoke方法的三个参数:

  • proxy:代表动态代理对象

  • method:代表正在执行的方法

  • args:代表调用目标方法时传入的实参

    动态代理就是在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法,可以理解为运行期间,对象方法的动态拦截,在拦截方法前后执行功能操作

    代理类在程序运行期间,创建的代理对象称之为动他代理对象,这种情况下,创建的代理对象,并不是事先在JAVA代码中定义好的,而是在运行期间,更具我们在动态代理对象中的指示,动态生成的,也就是说,你想获取那歌对象的代理.动态代理就会为你动态的生成这个对象的代理对象,动态代理可以对别代理对象的放大进行功能增强。

    有了动态代理的技术,那么就可以在不修改方法的源码的情况下,增强被代理对象的功能,在方执行前后做任何你想做的事

    1. 基于接口的动态代理

      • 提供者:JDK

      • 使用JDK官方的Proxy类创建代理对象

      • 注意:代理的目标对象必须实现接口

    2. 基于类的动态代理

      • 提供者:第三方 CGLib

      • 使用CGLib的Enhancer类创建代理对象

      • 注意:如果报 asmxxxx 异常,需要导入 asm.jar包

    public class LogProxy { /** * 生成对象的代理对象,对被代理对象进行所有方法日志增强 * 参数:原始对象 * 返回值:被代理的对象 * JDK 动态代理 * 基于接口的动态代理 * 被代理类必须实现接口 * JDK提供的 */ public static Object getObject(final Object obj){ /** * 创建对象的代理对象 * 参数一:类加载器 * 参数二:对象的接口 * 参数三:调用处理器,代理对象中的方法被调用,都会在执行方法。对所有被代理对象的方法进行拦截 */ Object proxyInstance = Proxy.newProxyInstance(obj.getClass().getClassLoader() , obj.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //方法执行前 long startTime = System.currentTimeMillis();

                Object result = method.invoke(obj, args);//执行方法的调用
    ​
                //方法执行后
                long endTime = System.currentTimeMillis();
                SimpleDateFormat sdf = new SimpleDateFormat();
                System.out.printf(String.format("%s方法执行结束时间:%%s ;方法执行耗时:%%d%%n"
                        , method.getName()), sdf.format(endTime), endTime - startTime);
                return result;
            }
        });
        return proxyInstance;
    }
    /**
     * 使用CGLib创建动态代理对象
     * 第三方提供的的创建代理对象的方式CGLib
     * 被代理对象不能用final修饰
     * 使用的是Enhancer类创建代理对象
     */
    public static Object getObjectByCGLib(final Object obj){
        /**
         * 使用CGLib的Enhancer创建代理对象
         * 参数一:对象的字节码文件
         * 参数二:方法的拦截器
         */
        Object proxyObj = Enhancer.create(obj.getClass(), new MethodInterceptor() {
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                //方法执行前
                long startTime = System.currentTimeMillis();
    ​
                Object invokeObject = method.invoke(obj, objects);//执行方法的调用
    ​
                //方法执行后
                long endTime = System.currentTimeMillis();
                SimpleDateFormat sdf = new SimpleDateFormat();
                System.out.printf(String.format("%s方法执行结束时间:%%s ;方法执行耗时:%%d%%n"
                        , method.getName()), sdf.format(endTime), endTime - startTime);
                return invokeObject;
            }
        });
        return proxyObj;
    }

    }

CGLib 底层原理 通过查看 Enhancer 类源码,最终也是生成动态代理类的字节码,动态代理类继承要被代理的类,然后实现其方法。

和 JDK Proxy 的实现代码比较类似,都是通过实现代理器的接口,再调用某一个方法完成动态代理的,唯一不同的是,CGLib 在初始化被代理类时,是通过 Enhancer 对象把代理对象设置为被代理类的子类来实现动态代理的。

CGLib 实现步骤 创建一个实现接口 MethodInterceptor 的代理类,重写 intercept 方法; 创建获取被代理类的方法 getInstance(Object target); 获取代理类,通过代理调用方法。

JDK Proxy 和 CGLib 的区别主要体现在以下方面:

JDK Proxy 是 Java 语言自带的功能,无需通过加载第三方类实现; Java 对 JDK Proxy 提供了稳定的支持,并且会持续的升级和更新,Java 8 版本中的 JDK Proxy 性能相比于之前版本提升了很多; JDK Proxy 是通过拦截器加反射的方式实现的; JDK Proxy 只能代理实现接口的类; JDK Proxy 实现和调用起来比较简单; CGLib 是第三方提供的工具,基于 ASM 实现的,性能比较高; CGLib 无需通过接口来实现,它是针对类实现代理,主要是对指定的类生成一个子类,它是通过实现子类的方式来完成调用的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值