JavaSE小结

  • FileInputStream(File file): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。

  • FileInputStream(String name): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。

当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有该文件,会抛出FileNotFoundException

  • 构造举例,代码如下:

public class FileInputStreamConstructor throws IOException{

public static void main(String[] args) {

// 使用File对象创建流对象

File file = new File(“a.txt”);

FileInputStream fos = new FileInputStream(file);

// 使用文件名称创建流对象

FileInputStream fos = new FileInputStream(“b.txt”);

}

}

3.2 字节输出流【OutputStream】

java.io.OutputStream抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。

  • public void close() :关闭此输出流并释放与此流相关联的任何系统资源。

  • public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。

  • public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。

  • public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。

  • public abstract void write(int b) :将指定的字节输出流。

小贴士:

close方法,当完成流的操作时,必须调用此方法,释放系统资源。

3.2.1 FileOutputStream类

OutputStream有很多子类,我们从最简单的一个子类开始。

java.io.FileOutputStream类是文件输出流,用于将数据写出到文件。

构造方法

  • public FileOutputStream(File file):创建文件输出流以写入由指定的 File对象表示的文件。

  • public FileOutputStream(String name): 创建文件输出流以指定的名称写入文件。

当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有这个文件,会创建该文件。如果有这个文件,会清空这个文件的数据。

  • 构造举例,代码如下:

public class FileOutputStreamConstructor throws IOException {

public static void main(String[] args) {

// 使用File对象创建流对象

File file = new File(“a.txt”);

FileOutputStream fos = new FileOutputStream(file);

// 使用文件名称创建流对象

FileOutputStream fos = new FileOutputStream(“b.txt”);

}

}

4.字符流

4.1 字符输入流【Reader】

java.io.Reader抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。

  • public void close() :关闭此流并释放与此流相关联的任何系统资源。

  • public int read(): 从输入流读取一个字符。

  • public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。

4.1.1 FileReader类

java.io.FileReader类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。

小贴士:

  1. 字符编码:字节与字符的对应规则。Windows系统的中文编码默认是GBK编码表。
idea中UTF-8
  1. 字节缓冲区:一个字节数组,用来临时存储字节数据。

构造方法

  • FileReader(File file): 创建一个新的 FileReader ,给定要读取的File对象。

  • FileReader(String fileName): 创建一个新的 FileReader ,给定要读取的文件的名称。

当你创建一个流对象时,必须传入一个文件路径。类似于FileInputStream 。

  • 构造举例,代码如下:

public class FileReaderConstructor throws IOException{

public static void main(String[] args) {

// 使用File对象创建流对象

File file = new File(“a.txt”);

FileReader fr = new FileReader(file);

// 使用文件名称创建流对象

FileReader fr = new FileReader(“b.txt”);

}

}

4.2 字符输出流【Writer】

java.io.Writer抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。

  • void write(int c) 写入单个字符。

  • void write(char[] cbuf)写入字符数组。

  • abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。

  • void write(String str)写入字符串。

  • void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。

  • void flush()刷新该流的缓冲。

  • void close() 关闭此流,但要先刷新它。

4.2.1 FileWriter类

java.io.FileWriter类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。

构造方法

  • FileWriter(File file): 创建一个新的 FileWriter,给定要读取的File对象。

  • FileWriter(String fileName): 创建一个新的 FileWriter,给定要读取的文件的名称。

当你创建一个流对象时,必须传入一个文件路径,类似于FileOutputStream。

  • 构造举例,代码如下:

public class FileWriterConstructor {

public static void main(String[] args) throws IOException {

// 使用File对象创建流对象

File file = new File(“a.txt”);

FileWriter fw = new FileWriter(file);

// 使用文件名称创建流对象

FileWriter fw = new FileWriter(“b.txt”);

}

}

六、Map集合有几种遍历方式,底层?


1. Map集合的遍历方式

Map集合主要有三种遍历方式:keySet()、entrySet()、values()。但是,如果从API层面上进行细分的话有7种。这三种各自都有两种形式,for循环和Iterator迭代。还有最后一种,如果你是JDK8以上版本,还可以使用Lambda表达式forEach遍历。

1.1 遍历方式的具体用法

1.1.1 keySet()方式遍历-------for循环

long keySetForStartTime = System.nanoTime();

for (String key : map.keySet()) {

map.get(key);

}

long keySetForEndTime = System.nanoTime();

1.1.2 keySet()方式遍历-------Iterator迭代

long keySetIteratorStartTime = System.nanoTime();

Iterator iterator1 = map.keySet().iterator();

while (iterator1.hasNext()) {

String key = iterator1.next();

map.get(key);

}

long keySetIteratorEndTime = System.nanoTime();

1.1.3 entrySet()方式遍历-------for循环

long entrySetForStartTime = System.nanoTime();

for (Map.Entry<String, String> entry : map.entrySet()) {

entry.getKey();

entry.getValue();

}

long entrySetForEndTime = System.nanoTime();

1.1.4 entrySet()方式遍历-------Iterator迭代

long entrySetIteratorStartTime = System.nanoTime();

Iterator<Map.Entry<String, String>> iterator2 = map.entrySet().iterator();

while (iterator2.hasNext()) {

Map.Entry<String, String> entry = iterator2.next();

entry.getKey();

entry.getValue();

}

long entrySetIteratorEndTime = System.nanoTime();

1.1.5 values()方式遍历-------for循环

long valuesForStartTime = System.nanoTime();

Collection values = map.values();

for (String value : values) {

//…

}

long valuesForEndTime = System.nanoTime();

1.1.6 values()方式遍历-------Iterator迭代

long valuesIteratorStartTime = System.nanoTime();

Iterator iterator3 = map.values().iterator();

while (iterator3.hasNext()) {

String value = iterator3.next();

}

long valuesIteratorEndTime = System.nanoTime();

1.1.7 JDK8-------Lambda表达式forEach遍历

long forEachStartTime = System.nanoTime();

map.forEach((key, value) -> {

//…

});

long forEachEndTime = System.nanoTime();

JDK8Lambda表达式的forEach方法,其实就是一种语法糖,让你的代码更加简洁,使用更加方便,深入源码,我们可以很轻易的发现,它其实就是对entrySet遍历方式的一种包装而已。不信你看下面我贴的forEach源码。

forEach源码。本方法since1.8版本

default void forEach(BiConsumer<? super K, ? super V> action) {

Objects.requireNonNull(action);

for (Map.Entry<K, V> entry : entrySet()) {

K k;

V v;

try {

k = entry.getKey();

v = entry.getValue();

} catch(IllegalStateException ise) {

// this usually means the entry is no longer in the map.

throw new ConcurrentModificationException(ise);

}

action.accept(k, v);

}

}

结果分析:

直接抛出结论,entrySet()方式比keySet()方式效率更高

在忽略其他条件下,对于同一种遍历方式而言,Iterator迭代比for循环效率高。

当然,上述的结论只是说出了一半。其实是分两种情况的。在元素数量大的情况下,entrySet()性能确实是优于keySet()的,越大越明显。同样的,在小数据量的情况下,keySet()效率更高一点。

为啥大数据量时,entrySet()效率高呢?

其实,keySet()遍历,其实是相当于遍历了两次,第一次是转换为Iterator对象,第二次才是根据key从Map中取出对应的value值。而entrySet()转成Entry对象,只遍历一次。

当然,还有其他的一些原因,比如,map.get(key),这一操作注定了是计算密集型操作,很耗费CPU,在此不再过多说明。

values()方式的说明

values(),顾名思义,它得到的是Map中value的集合,因此,想要获取value对应的key值比较困难,因此使用上还是看需求。

在日常的开发工作中推荐使用哪一种遍历方式呢?

直接说结论:推荐使用entrySet()遍历方式,这依然是不二之选。并不是很建议使用keySet方式。如果项目是JDK8以上的版本,直接使用forEach吧,底层原理一样,语法更好更简洁,何乐而不为呢?

2. Map集合的底层

2.1 HashMap 的底层原理

HashMap的数据结构

数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端。

数组:

​ ● 数组存储区间是连续的,占用内存严重,故空间复杂的很大。但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难;

链表

​ ● 链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:寻址困难,插入和删除容易。

哈希表

​ ● 那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案是肯定的,这就是我们要提起的哈希表。哈希表((Hash table)既满足了数据的查找方便,同时不占用太多的内容空间,使用也十分方便。

​ ● 哈希表有多种不同的实现方法,我接下来解释的是最常用的一种方法—— 拉链法,我们可以理解为“链表的数组” ,如图:

在这里插入图片描述

在这里插入图片描述

● 从上图我们可以发现哈希表是由数组+链表组成的,一个长度为16的数组中,每个元素存储的是一个链表的头结点。那么这些元素是按照什么样的规则存储到数 组中呢。一般情况是通过hash(key)%len获得,也就是元素的key的哈希值对数组长度取模得到。

● 比如上述哈希表中,12%16=12,28%16=12,108%16=12,140%16=12。所以12、28、108以及140都存储在数组下标为12的位置。

● HashMap其实也是一个线性的数组实现的,所以可以理解为其存储数据的容器就是一个线性数组。这可能让我们很不解,一个线性的数组怎么实现按键值对来存取数据呢?这里HashMap有做一些处理。

● 首先HashMap里面实现一个静态内部类Entry,其重要的属性有 key , value, next,从属性key,value我们就能很明显的看出来Entry就是HashMap键值对实现的 一个基础bean,我们上面说到HashMap的基础就是一个线性数组,这个数组就是Entry[],Map里面的内容都保存在Entry[]里面。

七、异常


1. 顶级父类Throwable

在这里插入图片描述

2. thorw与throws

2.1 throws

​ 1.throws用来声明一个方法可能产生的异常,不做任何处理,而是将异常往上传,谁调用就抛给谁。

​ 2.throws 可以声明多个,用逗号(,)隔开。

​ 3.throws表示出现异常的一种可能性,并不一定会发生这些异常。

​ 4.在方法的扩号后面使用throws声明此方法可能抛出的异常。

​ 5.如果调用此方法的地方想要解决此异常,就通过 try-catch捕获并处理此异常。

​ 6.若调用此方法的地方不想要解决此异常,就在调用这个方法的方法后面继续声明此异常。

​ 7.所到了main方法仍在继续声明异常的话,则此异常最后将交于JVM处理。

2.2 throw

​ 1.throw : 用来抛出一个具体的异常类型

​ 2.在方法体内部

​ 3.有两种方式要么是自己捕获异常try…catch代码块,要么是抛出一个异常(throws 异常),执行throw则一定抛出了某种异常。

在这里插入图片描述

八、对Class类对象(常用方法)、作用


public static Class<?> forName(String className):传入完整的“包.类”名称实例化Class对象

public Constructor[] getContructors() :得到一个类的全部的构造方法

public Field[] getDeclaredFields():得到本类中单独定义的全部属性

public Field[] getFields():得到本类继承而来的全部属性

public Method[] getMethods():得到一个类的全部方法

public Method getMethod(String name,Class..parameterType):返回一个Method对象,并设置一个方法中的所有参数类型

public Class[] getInterfaces() :得到一个类中锁实现的全部接口

public String getName() :得到一个类完整的“包.类”名称

public Package getPackage():得到一个类的包

获取Class类对象的三种方法

● Class.forName(“类的全类名”); //属于最为常用的获取方法,高频率用于JDBC中

● 类名.class //充当方法的参数较多

● 类对象.getClass() //在能创建类对象的情况下使用

九、线程(开启)


方法一:继承Thread

  1. 定义一个类继承Thread

  2. 重写run方法

  3. 创建线程对象

  4. 开启线程

public static void main(String[] args) {

//创建线程对象

MyThread myThread = new MyThread();

//开启线程

myThread.start();

}

//定义一个类继承Thread

public static class MyThread extends Thread {

//重写run方法

@Override

public void run() {

//todo task

super.run();

}

}

方法二:实现Runnable接口

  1. 定义一个类实现Runnable接口

  2. 重写run方法

  3. 在main方法(线程)中,创建线程对象,并启动线程.

① 创建线程类对象:

Thread thread = new Thread(myThread);

② 调用线程对象的start方法:

thread.start();

public static void main(String[] args) {

MyThread myThread = new MyThread();

//创建线程对象

Thread thread = new Thread(myThread);

//调用start方法

thread.start();

}

//定义一个类实现Runnable接口

public static class MyThread implements Runnable {

//重写run方法

@Override

public void run() {

//todo task

}

}

方法三:实现Callable接口

  1. 定义一个类实现Callable接口

  2. 重写call方法

  3. 在main方法(线程)中,创建Callable对象,创建任务将Callable对象传进来,创建线程对象将任务传进来,并启动线程.

① 创建Callable对象:

Callable c = new MyCallable();

② 创建任务将Callable对象传进来:

FutureTask task = new FutureTask<>©;

③ 创建线程类对象:

Thread thread = new Thread(task);

④ 调用线程对象的start方法:

thread.start();

public static void main(String[] args) {

//创建Callable对象

Callable c = new MyCallable();

//创建任务

FutureTask task = new FutureTask<>©;

//创建线程对象

Thread thread = new Thread(task);

//调用start方法

thread.start();

}

//定义一个类实现Callable接口

public static class MyCallable implements Callable {

//重写call方法

@Override

public Integer call() throws Exception {

//todo task

return null;

}

}

十、权限 static final


1. static

1.1 类变量

当 static 修饰成员变量时,该变量称为类变量。该类的每个对象都共享同一个类变量的值。任何对象都可以更改

该类变量的值,但也可以在不创建该类的对象的情况下对类变量进行操作。

​ ● 类变量:使用 static关键字修饰的成员变量。

1.2 静态方法

静态方法调用的注意事项:

​ ● 静态方法可以直接访问类变量和静态方法。

​ ● 静态方法不能直接访问普通成员变量或成员方法。反之,成员方法可以直接访问类变量或静态方法。

​ ● 静态方法中,不能使用this关键字。

​ ● static修饰的方法不能被重写

小贴士:

静态方法只能访问静态成员。

调用格式

被static修饰的成员可以并且建议通过类名直接访问。虽然也可以通过对象名访问静态成员,原因即多个对象均属于一个类,共享使用同一个静态成员,但是不建议,会出现警告信息。

格式:

// 访问类变量

类名.类变量名;

// 调用静态方法

类名.静态方法名(参数);

2. final

不可改变。可以用于修饰类、方法和变量。

​ ● 类:被修饰的类,不能被继承。

​ ● 方法:被修饰的方法,不能被重写。

​ ● 变量:被修饰的变量,不能被重新赋值。

十一、修饰符 public protected default private


在这里插入图片描述

十二、继承、多态


1. 继承

1.1 定义

继承:就是子类继承父类的属性行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。

1.2 好处

① 提高代码的复用性

② 类与类之间产生了关系,是多态的前提

1.3 继承的格式

通过 extends 关键字,可以声明一个子类继承另外一个父类,定义格式如下:

class 父类 {

}

class 子类 extends 父类 {

}

1.4 成员变量重名

子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用 super关键字,修饰父类成员变量,类似于之前学过的this

1.5 成员方法重名——重写(Override)

如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写 (Override)。

方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复 写。声明不变,重新实现

注意事项

① 子类方法覆盖父类方法,必须要保证权限大于等于父类权限。

② 子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。

父类空间优先于子类对象产生

在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构造方法调用时,一定先调用父类的构造方法。

Java只支持单继承,不支持多继承。

2. 多态

2.1 定义

多态: 是指同一行为,具有多个不同表现形式。

2.2 多态体现的格式

父类类型 变量名 = new 子类对象;

变量名.方法名();

Fu f = new Zi();

f.method();

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写后方法。

2.2 好处

实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展性与便利。

可以使程序编写的更简单,并有良好的扩展。

2.3 引用类型转换

向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。

当父类引用指向一个子类对象时,便是向上转型。

使用格式:

父类类型 变量名 = new 子类类型();

如:Animal a = new Cat();

向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。

一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。

使用格式:

子类类型 变量名 = (子类类型) 父类变量名;

如:Cat c =(Cat) a;

十三、工厂设计模式


工厂模式:实现了创建者与调用者的分离,即将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。

1. 简单工厂模式

用来生产同一等级结构中的任意产品。(对于增加新的产品,需要修改已有代码)

从命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的工厂类。

interface Car {

void run();

}

class Audi implements Car {

public void run() {

System.out.println(“奥迪在跑”);

}

}

class BYD implements Car {

public void run() {

System.out.println(“比亚迪在跑”);

}

}

//工厂类

class CarFactory {

//方式一

public static Car getCar(String type) {

if (“奥迪”.equals(type)) {

return new Audi();

} else if (“比亚迪”.equals(type)) {

return new BYD();

} else {

return null;

}

}

//方式二

// public static Car getAudi() {

// return new Audi();

// }

// public static Car getByd() {

// return new BYD();

// }

}

public class Client02 {

public static void main(String[] args) {

Car a = CarFactory.getCar(“奥迪”);

a.run();

Car b = CarFactory.getCar(“比亚迪”);

b.run();

}

}

调用者只要知道他要什么,从哪里拿,如何创建,不需要知道。分工,多出了一个专门生产 Car 的实现类对象的工厂类。把调用者与创建者分离。

总结:

简单工厂模式也叫静态工厂模式,就是工厂类一般是使用静态方法,通过接收的参数的不同来返回不同的实例对象。

缺点:对于增加新产品,不修改代码的话,是无法扩展的。违反了开闭原则(对扩展开放;对修改封闭)。

2. 工厂方法模式

用来生产同一等级结构中的固定产品。(支持增加任意产品)

为了避免简单工厂模式的缺点,不完全满足 OCP(对扩展开放,对修改关闭)。工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个(对于一个项目或者一个独立的模块而言)工厂类,而工厂方法模式有一组实现了相同接口的工厂类。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。

interface Car{

void run();

}

//两个实现类

class Audi implements Car{

public void run() {

System.out.println(“奥迪在跑”);

}

}

class BYD implements Car{

public void run() {

System.out.println(“比亚迪在跑”);

}

}

//工厂接口

interface Factory{

Car getCar();

}

//两个工厂类

class AudiFactory implements Factory{

public Audi getCar(){

return new Audi();

}

}

class BydFactory implements Factory{

public BYD getCar(){

return new BYD();

}

}

public class Client {

public static void main(String[] args) {

Car a = new AudiFactory().getCar();

Car b = new BydFactory().getCar();

a.run();

b.run();

}

}

总结:

简单工厂模式与工厂方法模式真正的避免了代码的改动了?没有。在简单工厂模式中,新产品的加入要修改工厂角色中的判断语句;而在工厂方法模式中,要么将判断逻辑留在抽象工厂角色中,要么在客户程序中将具体工厂角色写死(就像上面的例子一样)。而且产品对象创建条件的改变必然会引起工厂角色的修改。面对这种情况,Java 的反射机制与配置文件的巧妙结合突破了限制——这在Spring 中完美的体现了出来。

3. 抽象工厂模式

用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)

抽象工厂模式和工厂方法模式的区别就在于需要创建对象的复杂程度上。

而且抽象工厂模式是三个里面最为抽象、最具一般性的。抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象。

而且使用抽象工厂模式还要满足一下条件:

① 系统中有多个产品族,而系统一次只可能消费其中一族产品。

② 同属于同一个产品族的产品以其使用。

看过了前两个模式,对这个模式各个角色之间的协调情况应该心里有个数了,我就不举具体的例子了。

十四、单例设计模式


1. 饿汉式

顾名思义,饿汉式就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建。代码如下:

public class Singleton {

private static Singleton = new Singleton();

private Singleton() {

}

public static getSignleton(){

return singleton;

}

}

这样做的好处是编写简单,但是无法做到延迟创建对象。但是我们很多时候都希望对象可以尽可能地延迟加载,从而减小负载,

所以就需要下面的懒汉式

2. 懒汉式

单线程写法

这种写法是最简单的,由私有构造器和一个公有静态工厂方法构成,在工厂方法中对singleton进行null判断,如果是null就new一个来,最后返回singleton对象。这种方法可以实现延时加载,但是有一个致命弱点:线程不安全。如果有两条线程同时调用getSingleton()方法,就有很大可能导致重复创建对象。

public class Singleton {

private static Singleton singleton = null;

private Singleton(){

}

public static Singleton getSingleton()

{

if(singleton == null){

singleton = new Singleton();

}

return singleton;

}

}

考虑线程安全的写法

这种写法考虑了线程安全,将对singleton的null判断以及new的部分使用synchronized进行加锁。同时,对singleton对象使用volatile关键字进行限制,保证其对所有线程的可见性,并且禁止对其进行指令重排序优化。如此即可从语义上保证这种单例模式写法是线程安全的。注意,这里说的是语义上,实际使用中还是存在小坑的。

public class Singleton {

private static volatile Singleton singleton = null;

private Singleton(){

}

public static Singleton getSingleton(){

synchronized (Singleton.class){

if(singleton == null){

singleton = new Singleton();

}

}

return singleton;

}

}

十五、静态代理


1. 什么是静态代理模式

​ 代理的概念:生活中的代理是很常见的,比如代购、律师、中介等,他们都有一个共性就是帮助被代理人处理一些前前后后的事情。而被代理人只需要专注做自己要做的那部分事情就可以了。

​ Java中的代理也是类似的,代理模式可以实现帮助被代理者完成一些前期的准备工作和后期的善后工作,但是核心的业务逻辑仍然是由被代理者完成。

2. 静态代理模式的构成

静态代理模式由三个部分构成:

① 一个公共的接口

② 一个代理角色

③ 一个被代理角色

代码示例:

①:创建一个公共的接口,然后定义一个方法

//结婚的接口,接口中定义一个happyMarry的方法

public interface Marry{

void happyMarry();//愉快的结婚

}

②:创建一个代理角色

//创建一个代理角色(婚庆公司),婚庆公司帮你布置婚礼现场以及婚礼后的收尾工作

class WeddingCompany implements Marry{

private Marry target;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。

最新整理面试题
在这里插入图片描述

上述的面试题答案都整理成文档笔记。也还整理了一些面试资料&最新2021收集的一些大厂的面试真题

最新整理电子书

在这里插入图片描述

最新整理大厂面试文档

在这里插入图片描述

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

1. 什么是静态代理模式

​ 代理的概念:生活中的代理是很常见的,比如代购、律师、中介等,他们都有一个共性就是帮助被代理人处理一些前前后后的事情。而被代理人只需要专注做自己要做的那部分事情就可以了。

​ Java中的代理也是类似的,代理模式可以实现帮助被代理者完成一些前期的准备工作和后期的善后工作,但是核心的业务逻辑仍然是由被代理者完成。

2. 静态代理模式的构成

静态代理模式由三个部分构成:

① 一个公共的接口

② 一个代理角色

③ 一个被代理角色

代码示例:

①:创建一个公共的接口,然后定义一个方法

//结婚的接口,接口中定义一个happyMarry的方法

public interface Marry{

void happyMarry();//愉快的结婚

}

②:创建一个代理角色

//创建一个代理角色(婚庆公司),婚庆公司帮你布置婚礼现场以及婚礼后的收尾工作

class WeddingCompany implements Marry{

private Marry target;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-SFUnx7Xp-1713119003676)]

[外链图片转存中…(img-ZTAnUtbI-1713119003677)]

[外链图片转存中…(img-GMBkKGUe-1713119003677)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。

最新整理面试题
[外链图片转存中…(img-9PmTBxus-1713119003677)]

上述的面试题答案都整理成文档笔记。也还整理了一些面试资料&最新2021收集的一些大厂的面试真题

最新整理电子书

[外链图片转存中…(img-Cgyr8Imn-1713119003678)]

最新整理大厂面试文档

[外链图片转存中…(img-OWK7JwKo-1713119003678)]

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值