ღゝ◡╹)ノ❤️

集中一点,登峰造极!

  menu
137 文章
0 浏览
2 当前访客
ღゝ◡╹)ノ❤️

java基础

代理模式:aspectj,jdk,cglib

jdk

原理:实现同一个接口,让目标类以成员变量的方式实现方法增强。

优点:效率高。

缺点:代理的对象必须继承接口。

cglib

原理:继承目标类实现动态代理。

优点:不需要目标类实现接口。

缺点:被代理的类不能用final修饰。不能增强final或static修饰的方法。

aspecj

原理:编译的时候织入代码编译成class文件,静态代理

优点:可以增强任何类,任何方法。

总结:在项目中一般使用AspectJ,因为比较方便,使用几个注解就可以了。

接口和抽象类

相似性

  • 不能被实例化。
  • 能包含抽象方法,实现接口和抽象类的子类必须实现抽象方法。

区别

  • 接口中只能含有静态方法、默认方法和抽象方法,抽象类中可以含有普通方法。
  • 抽象类中可以含有构造器。让子类调用。
  • 接口里不能含有初始代码块。
  • 一个类可以有实现很多接口,但只能基础一个抽象类。
  • 接口更相当于一个约束,抽象类更相当于一个模板。

java8新特性

我主要了解有lambda表达式和Stream流。

lambda表达式

lambda表达式主要是简化了把类作为参数时的代码,原本如果把类作为参数需要new class然后再重写方法,但是如果使用lambda表达式的话,就只需要写参数好方法体了,甚至还可以引用别的类的静态方法,节省了很多代码。但是这个类必须是函数式接口。

Stream流

看过一点源码,他有中间操作和结束操作,他是每加一个操作,会增加一个过滤链节点,到结束的时候会生成一个完整的过滤链,然后再逐一进行对数据筛选或者其他操作。还可以选择多线程操作。效率方面如果是简单的操作不如for循环迭代,如果是复杂的操作效率差不太多,并且Stream的可读性会更好一点。

双亲委派机制

一个类加载器收到一个加载请求,不会尝试自己加载,而是会委托给父类加载器加载,如果父类加载器不能加载,然后尝试自己能否加载,自己加载不了会让字类加载器加载。

优点:

  • 防止类重复被加载。
  • 保护核心api的安全。

弊端:

即顶层的ClassLoader 无法访问底层的 ClassLoader 所加载的类。

第一次破坏双亲委派机制:jdk1.2之前。因为双亲委派机制是从jdk1.2才发明的。

第二次破坏双亲委派机制:打破弊端

第三次破坏双亲委派机制:程序追求动态性,如代码热替换,模块热部署。不再是双亲委派模型的树状结构,而是更复杂的网状结构。

高内聚,低耦合的理解

低耦合

我理解的低耦合对于编码上来说应该是尽量不采用硬编码,比如写一个功能时,应该尽量用接口的方法来写,这样以后调用改功能的时候可以传递不同的实现类,或者配置连接数据库参数的时候,应该尽量写到配置文件里面,而不是生硬的写到代码里面。

高内聚

功能内部类与类的控制程度要高,类之间参数应该尽量暴露在外面,防止想修改参数的时候不能修改。

引用拷贝,浅拷贝,深拷贝?

引用拷贝

引用拷贝会生成一个新的对象引用地址,但是两个最终指向依然是同一个对象。image-20201216222353944

 Son s1 = new Son("son1", 12);
 Son s2 = s1;

浅拷贝

浅拷贝会创建一个新对象,新对象和原对象本身没有任何关系,新对象和原对象不等,但是新对象的属性和老对象相同

    @Override
    protected Son clone() throws CloneNotSupportedException {
        return (Son) super.clone();
    }

深拷贝

在对引用数据类型进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量。

image-20201217111300466

@Override
protected Son clone() throws CloneNotSupportedException {
    Son son= (Son) super.clone();//待返回克隆的对象
    son.name=new String(name);
    son.father=father.clone();
    return son;
}

属性太多或层数太多怎么办?

image-20201217105458651

使用序列化和反序列化,因为反序列化的时候会重新创建所有的引用对象。

    public Student deepClone() {
        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
        try {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(bytesOut);
            objectOutputStream.writeObject(this);
            ByteArrayInputStream bytesIn = new ByteArrayInputStream(bytesOut.toByteArray());
            ObjectInputStream objectInputStream = new ObjectInputStream(bytesIn);
            return (Student) objectInputStream.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

作用: 如果想改变对象的值,可以调用方法的时候传递深拷贝的对象,否则使用浅拷贝。

序列化和反序列化?

序列化

将对象变成byte数组

  • JDK自带的ObjectOutPutStream。
  • 第三方的实现,如fastjson、jackson。转换成json对象再变成字节数组。

反序列化

将byte数组转成对象

作用:方便在网络上或者进程中进行传输。

为什么java代码一次编写,到处运行?

每个操作系统提供不同的jvm,jvm使class文件与操作系统解耦。

为啥包装类?

  • Java语言是面向对象的语言,其设计理念是“一切皆对象”。但8种基本数据类型却出现了例外,它们不具备对象的特性。正是为了解决这个问题,Java为每个基本数据类型都定义了一个对应的引用类型,这就是包装类。
  • 增强基本类型 增加了很多方法

面向对象?

面向对象是一种更优秀的程序设计方法,它的基本思想是使用类、对象、继承、封装、消息等基本概念进行程序设计。它从现实世界中客观存在的事物出发来构造软件系统,并在系统构造中尽可能运用人类的自然思维方式,强调直接以现实世界中的事物为中心来思考,认识问题,并根据这些事物的本质特点,把它们抽象地表示为系统中的类,作为系统的基本构成单元,这使得软件系统的组件可以直接映像到客观世界,并保持客观世界中事物及其相互关系的本来面貌。

hashCode()和equals()的关系?

hashCode()用于获取哈希码(散列码),eauqls()用于比较两个对象是否相等,它们应遵守如下规定:

  • 如果两个对象相等,则它们必须有相同的哈希码。
  • 如果两个对象有相同的哈希码,则它们未必相等。

比如在对象使用hashset的时候,根据hashcode来决定散列在哪个桶里,然后再对桶里的元素去重。假如两个对象equals相等但是hashcode不相等,他们肯定会被分配到不同的桶里。这样就不能去重,就逻辑错误了。

java异常接口

Throwable是异常的顶层,他有两个直接子类分别是Error和Exception。

Error一般与虚拟机有关,比如oom,栈溢出,动态链接失败。这种错误会直接导致程序崩溃。

Exception可分为Checked异常和Runtime异常,Runtime异常不需要强制捕获,如数组越界、空指针、非法参数。Cheked异常一般与IO有关,需要强制捕获。

java反射作用?

  • 增加了灵活性,使用反射进行加载实例调用方法,实例不需要import。实现解耦。springIOC,jdk动态代理
  • 可以在程序运行的时候,动态将类加载进去。
  • 获取方法上的注解,然后根据注解进行一些列操作。

java值传递和址传递?

我了解到的java里面应该是只有值传递没有

值传递:将实际参数赋值一份传递到函数中,这样函数无论对参数做什么修改都不会影响原来的参数。

引用传递:将实际参数的地址传递给函数,这样函数中对参数的操作会影响原来的参数。

java传递引用数据类型的时候,如果给方法中的参数重新new一下赋值,并不会改变原来的对象,所以java 中并没有引用传递。

String为什么设计成不可变类?

1,便于实现字符串常量池。

java中,大量使用了String这种类型,如果每次声明一个Sting都新建一个对象,那将会造成极大的空间资源浪费。所以提出了字符串常量池的概念。

如果,String是可变的,那么另一个指向该对象的引用也改变了。

2,多线程安全。

3,加快处理速度。

hashcode计算一次就可以缓存起来了,不需要重新计算。

为什么Integer负数比正数的绝对值大一

因为正数已经有0x00000000 00000000 00000000 0000000来表示0,所以负数没必要再浪费一个位置表示0,所以用来表示比原来小1的数

如何自定义一个加载器?

https://www.cnblogs.com/xrq730/p/4847337.html


标题:java基础
作者:哇哇哇哇
地址:https://wuxiangshi.vip/articles/2022/02/17/1645111786188.html