Java基础知识总结(中)

2021-04-30  本文已影响0人  _code_x

谈谈对面向对象/面向过程的理解?

应用举例:

总结:

类与对象的关系

面向对象的三大特性?

ps:A a = New B(); 向上转型是JAVA中的一种调用方式,是多态的一种表现。向上转型并非是将B自动向上转型为A的对象,相反它是从另一种角度去理解向上两字的:它是对A的对象的方法的扩充,即A的对象可访问B从A中继承来的和B重写A的方法,其它的方法都不能访问,包括A中的私有成员方法。向上转型一定是安全的,没有问题的,正确的(主要是为了提高扩展性和维护性)。但是也有一个弊端:对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。

访问修饰符

修饰符 当前类 同包 子类 其他包
private v × × ×
default v v × ×
protected v v v ×
public v v v v

重载与重写区别

重载发生在同一个类中,方法名必须相同,参数列表(参数个数、类型不同,多个参数的顺序)必须不同,方法返回值和访问修饰符可以不同,发生在编译时(编译器会根据参数列表进行匹配,确定方法,如果失败,编译器报错,这叫做重载分辨)。

每个重构的方法(构造函数)都必须有独一无二的参数类型列表。最常见的地方就是构造器的重载,即构造函数。注意:构造方法不能被重写!

public class Test1 {
    public void out(){
        System.out.println("参数"+null);
    }
    // 重载 ------ -----------方法名必须相同-------------------------------
    // 参数数目不同
    public void out(Integer n){
        System.out.println("参数"+n.getClass().getName());
    }
 
    // 参数类型不同
    public void out(String string){
        System.out.println("参数"+string.getClass().getName());
    }
 
    public void out(Integer n ,String string){
        System.out.println("参数"+n.getClass().getName()+","+string.getClass().getName());
    }
    //参数顺序不同
    public void out(String string,Integer n){
        System.out.println("参数"+string.getClass().getName()+","+n.getClass().getName());
    }
    
    public static void main(String[] args) {
        Test1 test1 = new Test1();
        test1.out();
        test1.out(1);
        test1.out("string");
        test1.out(1,"string");
        test1.out("string",1);
    }
}

重写子类对父类中允许访问的方法进行重新编写(覆盖父类的方法),或者实现类对接口的重写,方法名和参数列表必须相同(可以理解为外壳不变)!

返回值范围和抛出异常范围小于等于父类,访问修饰符范围大于等于父类(子类方法的访问权限更大),发生在运行时;

便于记忆:两同(方法名和参数列表)两小(返回值和抛出异常的范围)一大(访问权限)!

注意:如果父类方法的访问修饰符为private,则子类不能重写该方法。

class Test{
    public void out(){
        System.out.println("我是父类方法");
    }
    // 子类不能重写此方法
    private void out1(){
        System.out.println("我是父类方法");
    }
}
 
public class Test1 extends Test{
    @Override
    // 方法名与参数列表必须完全一致
    public void out() {
        System.out.println("我是重写后的子类方法");
    }
 
    public static void main(String[] args) {
        Test test = new Test();
        test.out();
        test = new  Test1();
        test.out();
    }
}

总结

重写(Overriding) 重载(Overloading)
应用场景 父子类、接口与实现类 本类
方法名称 必须一致 必须一致
参数列表 一定不能修改(必须一致) 必须修改(每个重构方法参数列表独一无二)
返回类型 一定不能修改(必须一致) 可以修改
异常 可以减少或删除,但不能扩展 可以修改

接口与抽象类的异同点与总结?

对于面向对象编程来说,抽象是它的一大特征之一。在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类。这两者有太多相似的地方,又有太多不同的地方。

两者的相同点:

主要区别:

解决的问题:

传递的信息(本质是否改变)

应用场景:

注意:抽象类不能用final修饰,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾。

补充:抽象方法

//没有方法体,有abstract关键字做修饰
public abstract void xxx();

抽象类是为了把相同的但不确定的东西的提取出来,为了以后的重用。定义成抽象类的目的,就是为了在子类中实现抽象方法。例如,构造一个动物类,包括“吃”,‘嚎叫’等方法。由于不同动物的 吃 和 嚎叫 是不同的,可以将 吃 和 嚎叫定义为抽象类。在继承这个动物类时,不同的动物再实现不同的 吃 和 嚎叫方法。

抽象类的使用注意点:

hashCode与equals的区别和联系

hashCode概述

为什么要有hashCode?

以“HashSet如何检查重复”为例子来说明为什么要hashCode:

什么时候重写hashCode?

重写equals,为什么还要重写hashCode呢?

ps:hashCode()的默认行为是对堆上的对象产生独特值(默认返回当前对象的地址)。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)。

hashCode与equals区别:两者的区别主要体现在性能和可靠性

补充:阿里开发规范

super函数用法,与this能否同时使用?super和this关键字区别?

super()和this()能不能同时使用

不能同时使用,this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。

this关键字:理解为本类的,先查找本类,如果本类没有再查找父类!

class People{
    String name;
    public People(String name){//正确写法
        this.name = name;
    }
    public People(String name){//错误写法
        name = name;//当一个方法的形参与成员变量的名字相同时,就会覆盖成员变量
    }
}

super关键字:理解为父类的,不查找本类,直接调用父类的结构

常用情况:当子类重写了父类的方法后,我们想在子类方法中调用父类中被重写的方法时,必须显示的使用super.方法,表示调用的是父类中被重写的方法

成员变量与局部变量区别

变量:在程序执行的过程中,在某个范围内其值可以发生改变的量。从本质上讲,变量其实是内存中的一小块区域

成员变量:方法外部,类内部定义的变量;局部变量:类的方法中的变量。区别如下:

使用原则:就近原则,首先在局部范围找,有就使用;接着在成员位置找。

静态变量与实例变量的区别

两者主要区别在隶属对象、存储位置和存在个数:

静态方法与实例方法的区别,为什么静态方法不能调用非静态成员?

两种方法主要区别在外部调用方式和访问本类成员的限制:

由于静态方法可以不通过对象进行调用,静态方法属于类,不属于对象。静态资源在类初始化的过程加载的,非静态资源在类new的过程中加载的。因此静态方法里,不能调用和访问其他非静态成员。

Java内部类的作用是什么,有哪些分类?应用场景?

为什么需要内部类?

内部类分类:

静态内部类和非静态内部类的区别:

在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是? 子类的初始化顺序?

目的:帮助子类做初始化工作。子类初始化顺序

一个类的构造方法的作用是什么? 若一个类没有声明构造方法,该程序能正确执行吗? 构造方法有哪些特性?

构造方法主要作用:完成对类对象的初始化

没有声明类的构造方法,程序也可以执行,因为类有默认的不带参数的构造方法。

构造方法的特性:

创建一个对象用什么运算符?对象实体与对象引用有何不同?

new 运算符:

对象引用:一个对象引用可以指向 0 个或 1 个对象(一根绳⼦可以不系⽓球,也可以系一个⽓球)

对象实体:一个对象可以有 n 个引用指向它(可以用 n条绳子系住一个气球)。

ps:对象引用看成绳子,对象看成气球。

Java 按值调用还是引用调用(传递)?

值传递 引用传递
根本区别 会创建副本(Copy) 不创建副本(直接使用参数)
导致结果 形参和实参本质互不影响 形参影响实参

ps:实参与形参:实际参数是调用有参方法的时候真正传递的内容(传给方法的值),而形式参数是用于接收实参内容的参数。

Java 总是按值传递,分析如下:

基本类型 - 值传递 引用类型 - 值传递

另外比较常见的例子:

    public static void main(String[] args) {
        int[] arr = { 1, 2, 3, 4, 5 };
        System.out.println(arr[0]);  // 1
        change(arr);
        System.out.println(arr[0]);  // 0
    }

    public static void change(int[] array) {
        // 将数组的第一个元素变为0
        array[0] = 0;
    }

上边的代码中array作为arr的引用的拷贝,但两者都是指向堆中的数组对象,所以,外部对引用对象的改变会反映到对象本身。

对比看一下,如果是引用传递呢?因为引用传递是不复制的,直接使用参数,如下图:这时候函数把指针a=null就指针就置空了,函数外也无法再通过指针访问对象了

引用传递

综上所述:Java是值传递,即使传的是引用也不是引用传递,值的内容为对象的引用(赋值修改,但是对象本身没有改变)。

JDK8新特性?

注意lamda表达式的优缺点和应用场景:

应用场景:Lamda表达式主要用于替换以前广泛使用的匿名内部类,各种回调,比如事件响应器、传入Thread类的Runnable等。

(1)使用() -> {} 替代匿名类

//Before Java 8:
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Before Java8 ");
    }
}).start();

//Java 8 way:
new Thread(() -> System.out.println("In Java8!"));

// Before Java 8:
JButton show =  new JButton("Show");
show.addActionListener(new ActionListener() {
     @Override
     public void actionPerformed(ActionEvent e) {
           System.out.println("without lambda expression is boring");
        }
     });

// Java 8 way:
show.addActionListener((e) -> {
    System.out.println("Action !! Lambda expressions Rocks");
});

(2)使用内循环替代外循环

外循环:描述怎么干,代码里嵌套2个以上的for循环的都比较难读懂;只能顺序处理List中的元素;
内循环:描述要干什么,而不是怎么干;不一定需要顺序处理List中的元素

//Before Java 8:
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Before Java8 ");
    }
}).start();

//Java 8 way:
new Thread(() -> System.out.println("In Java8!"));

// Before Java 8:
JButton show =  new JButton("Show");
show.addActionListener(new ActionListener() {
     @Override
     public void actionPerformed(ActionEvent e) {
           System.out.println("without lambda expression is boring");
        }
     });

// Java 8 way:
show.addActionListener((e) -> {
    System.out.println("Action !! Lambda expressions Rocks");
});

(3)支持函数编程

为了支持函数编程,Java 8加入了一个新的包java.util.function,其中有一个接口java.util.function.Predicate是支持Lambda函数编程

(4)用管道方式处理数据更加简洁

Java 8里面新增的Stream API ,让集合中的数据处理起来更加方便,性能更高,可读性更好

jar包和war包的主要区别

(1)jar包:JAR包是类的归档文件,JAR 文件格式以流行的 ZIP 文件格式为基础。与 ZIP 文件不同的是,JAR 文件不仅用于压缩和发布,而且还用于部署和封装库、组件和插件程序,并可被像编译器和 JVM 这样的工具直接使用。

(2)war包:war包是JavaWeb程序打的包,war包里面包括写的代码编译成的class文件,依赖的包,配置文件,所有的网站页面,包括html,jsp等等。一个war包可以理解为是一个web项目,里面是项目的所有东西。

(1)jar包里的com里放的就是class文件,配置文件,但是没有静态资源的文件,大多数 JAR 文件包含一个 META-INF 目录,它用于存储包和扩展的配置数据,如安全性和版本信息。

(2)war包里的WEB-INF里放的class文件和配置文件,META-INF和jar包作用一样,但是war包里还包含静态资源的文件。

(1)部署普通的spring项目用war包就可以
(2)部署springboot项目用jar包就可以,因为springboot内置tomcat。

(1)war包和项目的文件结构保持一致,jar包则不一样。
(2)jar包里没有静态资源的文件(index.jsp)

巨人的肩膀

https://blog.csdn.net/qq_42014192/article/details/89707483
https://blog.csdn.net/xlgen157387/article/details/88087963
https://blog.csdn.net/q5706503/article/details/82910428
https://www.cnblogs.com/banml/p/11767305.html
https://blog.csdn.net/weixin_40995778/article/details/79771513
https://www.cnblogs.com/wangxin37/p/6737522.html

上一篇下一篇

猜你喜欢

热点阅读