转载声明:文章来源https://blog.csdn.net/weixin_44480968/article/details/129853380
一、面向对象和面向过程的区别
先说概念:
面向过程:是指分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;
面向对象:是指构成问题的事物分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题过程中的行为。
再说区别(举例说明最好,下面以汽车制造商设计生产线控制系统为例):
面向过程的形式:在这个系统中,将整个汽车零件装配过程分解为一系列步骤,每个步骤都是一个独立的函数,按照特定的逻辑依次执行。
面向对象的形式:在这个系统中,汽车零部件被视为对象,每个对象都有自己的属性和方法。例如,一个轮胎对象可能有属性如品牌、型号、尺寸,方法如安装、更换、检查。生产线上的机器人可以通过调用这些方法来完成组装工作。
二、面向对象的三大特征
封装
封装是指把一个对象的状态信息(也就是属性)隐藏在对象内部,不允许外部对象直接访问对象的内部信息。但是可以提供一些可以被外界访问的方法来操作属性。
举例说明:就好像我们看不到挂在墙上的空调的内部的零件信息(也就是属性),但是可以通过遥控器(方法)来控制空调。如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。就好像如果没有空调遥控器,那么我们就无法操控空凋制冷,空调本身就没有意义了(当然现在还有很多其他方法 ,这里只是为了举例子)。
继承
不同类,可能有很多个相同的属性和方法。继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承,可以快速地创建新的类,可以提高代码的重用,程序的可维护性,节省大量创建新类的时间 ,提高我们的开发效率。
举例说明:例如,猫(Cat)、狗(Dog)等动物,它们都有动物的一般特征(比如能够吃东西,能够发出声音),不过又在细节上有区别(不同动物吃的食物不同,叫声不一样)。
注:这里有个问题:java支持单继承,为什么不支持多继承?Java为什么不支持多继承?
多继承会导致这种有歧义的情况存在,例如:类 B 和类 C 继承自类 A,且都重写了类 A 中的同一个方法,而类 D 同时继承了类 B 和类 C,那么此时类 D 会继承 B、C 的方法,那对于 B、C 重写的 A 中的方法,类 D 会继承哪一个呢?
多态
多态,顾名思义,表示一个对象具有多种的状态。具体表现为父类的引用指向子类的实例。
举例说明:谢谢你这句话,在很多国家都有不同的说法。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际 上新加子类更容易获得多态功能。
三、==和equals区别
1.== 对于基本类型和引用类型的作用效果是不同的
对于基本数据类型来说,== 比较的是值。
对于引用数据类型来说,== 比较的是对象的内存地址。
因为 Java 只有值传递,所以,对于 == 来说,不管是比较基本数据类型,还是引用数据类型的变量,其本质比较的都是值,只是引用类型变量存的值是对象的地址。
2.equals() 不能用于判断基本数据类型的变量,只能用来判断两个对象是否相等
equals()方法存在于Object类中,而Object类是所有类的直接或间接父类,因此所有的类都有equals()方法。equals() 方法存在两种使用情况:
类没有重写 equals()方法 :通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象,使用的默认是 Object类equals()方法。
类重写了 equals()方法 :一般我们都重写 equals()方法来比较两个对象中的属性是否相等;若它们的属性相等,则返回 true(即,认为这两个对象相等)。
四、HashCode相关
1. 什么是HashCode?
HashCode 是一个散列值或哈希码,它是对象的整数标识符。在Java中,HashCode通常被用于数据结构中,如HashMap、HashSet和Hashtable来提高查找性能。当一个对象被放置到这些数据结构中时,系统会根据该对象的HashCode来确定它对应的位置,以便快速访问该对象。
HashCode通过将对象的内容映射到一个数字上来生成。这个数字的计算过程称为散列函数或哈希函数。hashCode()方法负责计算对象的散列值,该方法定义在Object类中并可以被子类覆盖。如果一个类没有覆盖hashCode()方法,则使用从Object类继承的默认实现。
2. 如果两个对象具有相同的HashCode,它们是否相等?
如果两个对象的HashCode相同,它们不一定相等。这是由于散列函数的性质,称为哈希冲突。哈希冲突是指当两个不同的对象被分配到相同的散列桶中时发生的情况。因此,即使两个对象具有相同的HashCode,它们在内容上也可能不同。
因此,在判断两个对象是否相等时,不能仅依赖于它们的HashCode,而应该使用equals()方法来比较它们的内容。建议重写equals()方法,以确保正确地比较对象的属性值。
判断其是否相等的正确方法应该是:
如果两个对象的hashCode 值相等,那这两个对象不一定相等(哈希碰撞);
如果两个对象的hashCode 值不相等,我们就可以直接认为这两个对象不相等;
如果两个对象的hashCode 值相等并且equals()方法也返回 true,我们才认为这两个对象相等;
3. 如何地重写equals()和hashCode()方法?
equals()方法用于判断两个对象是否相等。默认情况下,equals()方法会比较两个对象的引用地址(即内存地址),而不是对象的属性值。因此,如果要比较两个对象的属性值是否相等,就需要重写equals()方法。
在equals()方法中,比较对象的每个属性是否相等。如果所有属性都相等,则认为两个对象相等。重写equals()方法时,要注意满足以下四个条件:
自反性:任何非null的对象必须与它自己相等。
对称性:如果x.equals(y)返回true,则y.equals(x)也必须返回true。
传递性:如果x.equals(y)返回true,并且y.equals(z)也返回true,则x.equals(z)也必须返回true。
一致性:如果两个对象相等,则多次调用equals()方法应该始终返回true,除非两个对象的属性发生变化。
hashCode()方法用于计算对象的散列值。在Java中,散列表的实现通常使用散列值来确定对象在表中的位置。因此,如果两个对象的散列值相同,它们可能被放置在同一个位置上,从而导致性能问题。因此,hashCode()方法也需要被重写。
在hashCode()方法中,为每个属性计算一个哈希码,并将它们组合成一个总的哈希码。通常情况下,可以使用Java提供的Objects.hash()方法来计算哈希码。
重写hashCode()方法时,要注意满足以下两个条件:
如果两个对象相等,则它们的hashCode()方法必须返回相同的值。
如果两个对象不相等,则它们的hashCode()方法应该尽可能返回不同的值。
五、String StringBuffer 和 StringBuilder 的区别是什么?
String、StringBuffer和StringBuilder都是Java中用于处理字符串的类,它们之间的区别主要在于其线程安全性、执行速度以及可变性方面。
String是不可变的,每次对String的操作都会产生一个新的String对象,因此在频繁进行字符串拼接等操作时效率较低。
StringBuffer和StringBuilder都是可变的,支持动态添加、删除、修改字符串内容。但是,StringBuffer是线程安全的,方法前使用了synchronized关键字来进行同步,所以在多线程环境下可以保证数据的安全性;
StringBuilder则是非线程安全的,方法没有使用同步机制,执行速度比StringBuffer稍快,但在多线程环境下可能会发生竞态条件问题。
因此,如果操作少量的数据: 适用 String;如果在单线程环境下需要频繁进行字符串拼接等操作,建议使用StringBuilder;如果在多线程环境下需要进行字符串操作,建议使用StringBuffer。
六、String类为什么用final关键字修饰?
在Java中,final关键字用于表示一个常量或不可变的值。在String类中,使用final关键字修饰字符串对象是为了防止其被修改。因为String是一个非常常用的类,经常被用来存储重要的数据,如果String对象可以被修改,那么就可能会导致程序出错或数据被篡改。如果为了避免安全隐患,在它每次出现时都用final来修饰,这无疑会降低程序的执行效率,所以干脆直接将其设为final,提高效率。
因此,将String类中的字符串对象声明为final是为了保证它们的不可变性,这样一旦一个String对象被创建,它的值就不能再被修改了,从而增强了程序的安全性和稳定性。
七、重载和重写区别
重载是让类以统一的方式处理不同类型数据的一种手段。多个同名函数同时存在,具有不同的参数个数/类型,根据输入数据的不同,做出不同的处理;其规则如下:
方法名必须相同
参数类型、个数、顺序至少有一个不相同
不能重载只有返回值不同的方法名
存在于父类和子类、同类中
重写是当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,覆盖父类的方法;发生在运行期,是子类对父类方法的重新改造,它的外部样子不能进行改变,但它的内部逻辑可以发生改变。其规则如下:
方法名、参数列表必须相同;
如果父类方法访问修饰符为 private/final/static, 那么它的子类就不能重写该方法,但是被 static 修饰的方法能够被再次声明;
构造方法无法被重写;
八、Java基本数据类型有哪些?
Java有8种基本数据类型,包括6种数字类型、1种布尔类型、1种字符类型;
数据类型 占用空间 取值范围 默认值
这八种基本类型都有对应的包装类分别为:Byte、Short、Integer、Long、Float、Double、Character、Boolean
九、讲述一下final、static、this、super关键字
final:final关键字可以用来修饰类、方法和变量,它表示该元素在定义后不能被修改或继承。被final修饰的变量称为常量,一旦被初始化之后就不能再次赋值了。
static:static关键字主要用来定义静态变量和静态方法。静态变量指的是所有实例对象共享同一个变量,而不是每个实例对象都有自己独立的变量。静态方法指的是不需要创建实例对象就可以调用的方法。
this:this关键字代表当前对象,可以用于区分局部变量和成员变量。比如,在方法中如果有一个局部变量和一个成员变量同名,那么使用this关键字就可以访问成员变量而不是局部变量。
super:super关键字代表父类对象,可以用于调用父类的构造方法和成员变量、方法。比如,在子类中如果想要调用父类的构造方法,就可以使用super关键字。同时,如果子类中有与父类同名的成员变量或方法,也可以使用super关键字引用父类的成员变量或方法。
十、抽象类和接口有什么区别?
抽象类和抽象方法:抽象类和抽象方法都必须使用abstract来修饰,抽象类不能被实例化,只能通过其子类给他赋值,普通类里有的,抽象类都有。抽象类就相当于是一个模板,上面描述了一些字段、方法,但不会去实现和填充。就相当于只说话不干活的老板,只用吩咐手下去干活!
接口:定义的是多个类共同的行为规范,这些行为是与外部交流的通道,这就意味着接口里通常定义的是一组公用的方法。接口的本质是契约,标准,规范,就像我们的法律一样,制定好后大家都要遵守。
抽象类和接口之间的主要区别在于:
实现方式:抽象类是一个类,可以包含属性、方法和构造函数等组件,而接口只能包含方法声明和常量。因此,抽象类可以实现一些默认行为,而接口只能定义规范。
继承限制:一个类只能继承一个抽象类,但是可以实现多个接口。这是因为继承一个抽象类通常表示"是一个"(is-a)关系,而实现一个接口通常表示"具有某种能力"(can-do)关系。
方法实现:抽象类可以包含已经实现的方法,而接口中的所有方法都必须由实现该接口的类提供具体的实现。
访问修饰符:抽象类可以包含public、protected和default访问修饰符的成员,而接口中的成员默认都是public的。
十一、Java异常有哪些?如何处理?
Java中的异常可以分为两种类型:RuntimeException(运行时异常)和CheckedException(检查异常)
CheckedException(检查异常):这种异常是在编译时就可以被捕获并处理的。例如,FileNotFoundException(文件未找到异常)等。对于这种异常,必须使用try-catch语句或者throws子句进行处理,否则程序将无法通过编译。
RuntimeException(运行时异常):这种异常是在运行时才会发生的,并且不需要在代码中显式地声明或捕获。例如,NullPointerException(空指针异常)、ArrayIndexOutOfBoundsException(数组下标越界异常)等。通常,这些异常是由程序员错误造成的,如访问null对象或者访问不存在的数组索引等。如果不进行处理,这些异常会导致程序崩溃。
处理异常的方法包括:
使用try-catch语句来捕获和处理异常。try块中的代码可能会抛出异常,而catch块中的代码用来处理异常。如果try块中的代码抛出了异常,那么程序就会跳转到catch块中。在catch块中,可以选择处理异常或者将其重新抛出。
使用finally语句块来执行清理操作。finally块中的代码总是会被执行,无论是否发生异常。通常,在finally块中释放资源、关闭文件等操作。
使用throws关键字声明方法可能会抛出的异常。如果该方法中的代码抛出了这些异常之一,那么调用该方法的代码负责处理这些异常。
自定义异常类。如果Java提供的异常类无法满足需求,可以通过继承Exception类(或其子类)来自定义异常类。然后,就可以像使用Java预定义的异常类一样使用自定义异常类。
帖子还没人回复快来抢沙发