Java基础模块

Java基础模块

一、Java基础模块 1、Java为什么不支持多继承? 在Java语言中,不支持多继承的主要原因是为了简化语言设计和避免潜在的问题(如:菱形继承),同时又因为在实际工作中,确实很少用到多继承,所以在Java语言中,并不支持多继承。 具体来说,Java不支持多继承的原因又有以下几个: a、避免菱形继承

一、Java基础模块

1、Java为什么不支持多继承?

在Java语言中,不支持多继承的主要原因是为了简化语言设计和避免潜在的问题(如:菱形继承),同时又因为在实际工作中,确实很少用到多继承,所以在Java语言中,并不支持多继承。

具体来说,Java不支持多继承的原因又有以下几个:

a、避免菱形继承问题:菱形继承问题也叫钻石继承,指的是当一个类从两个不同的父类继承相同的方法,而再次被子类继承时会导致调用该方法的二义性,这会造成设计上和编译上的困惑和复杂性。

b、简化编程语言:Java的设计目的之一是简化语言,使其易于学习和使用。多继承在类的设计和使用上增加了复杂性,包括方法解析的问题、命名冲突、继承混乱等。

c、避免多重继承的层次膨胀:多继承可能导致继承层次的膨胀,如果一个类继承多个父类,再将该类作为基础类,避免子类再继承该类,会造成继承层次的复杂和混乱。

扩展:

如果想要在Java中实现“多继承”可以使用以下方案:

①实现多接口:Java语言中是支持类实现多个接口的,所以我们可以使用一个类实现多个接口,从而获得多个接口定义的行为。通过接口可以实现类似多继承的效果,同时避免了多继承可能引发的冲突和复杂性问题。

②组合多个类:使用组合类的方式,通过将多个类作为成员变量组合到一个类中,以实现复用和组合多个类的功能。通过使用组合,一个类可以间接的获得多个类的功能。

③继承加接口:在某些情况下,一个类可以继承一个类同时实现一个或多个接口,这样的组合可以使类同时继承父类的属性和方法,并实现接口定义的行为。

2、==和equals有什么区别?

==用于基础数据类型时,是用来比较两个变量值是否相等的,而对于引用类型来说,是用来比较对象的引用是否相同,而equals默认是比较两个对象的引用是否相同,但大部分时候都会被重写为比较两个对象的值是否相同。

例如,对于Object来说,==和equals都是一样的,都是用来比较两个对象的引用是否相同,而String或Integer等类中,又重写了equals让其变成了比较值是否相同(而非引用是否相同)。

所以,我们通常会使用==来对比两个对象的引用是否相同,而使用equals对比两个值是否相同(前提条件是重写了equals方法)。

对于Object来说,equals方法的底层实现就是“==”,如以下源码所示:

public boolean equals(Object obj){
	return (this == obj);
}

所以,对于Object对象来说,equals和==是一样的,都是比较对象的引用是否相同。

但是,Integer中的equals实现源码如下:

public boolean equals(Object obj) {​
	if (obj instanceof Integer) {​
		return value == ((Integer)obj).intValue();​
	}​
	return false;​
}​

从上述源码可以看出,Integer 中会先将 Integer 对象转换成基础类型 int 值来进行比较,所以此时就不再是对比两个对象的引用了,而是对比两个对象的值是否相等。​

String 中的 equals 实现源码如下:

public boolean equals(Object anObject) {​
	if (this == anObject) { // 引用相同返回 true,引用相同,那么值肯定相同了​
	return true;​
	}​
	return (anObject instanceof String aString)​&& (!COMPACT_STRINGS || this.coder == aString.coder)​&& StringLatin1.equals(value, aString.value); // equals 为下面的 equals 方法​
}​
@IntrinsicCandidate​
public static boolean equals(byte[] value, byte[] other{​
	if (value.length == other.length) {​
		for (int i = 0; i < value.length; i++) { // 循环每个字符对比(本质是比较 String 的值)​
			if (value[i] != other[i]) {​
				return false;​
			}​
		}​
		return true;​
	}​
	return false;​
}

从 String 中的 equals 中可以看出,它和 Integer 一样,是将 Object 中的引用比较重写成了值比较了。​

​知识扩展:如何实现自定义equals方法?​

如果是我们的业务类中想要重写 equals 方法,实现对象值的比较(非引用),可以这样实现:​

public class Person {​
	private String name;​
	private int age;​
	// 忽略构造方法和 Getter、Setter 方法......​
	@Override​
	public boolean equals(Object obj) {​
		if (this == obj) {​
			return true;​
		}​
		if (obj == null || getClass() != obj.getClass(){​
			return false;​
		}​
		Person other = (Person) obj;​
		return this.age==other.age&&this.name.equals(other.name);​
	}​
}

3、返回值不同算方法重载吗?为什么?

返回值不同不算方法重载。

方法重载(Overloading)是指在同一个类中定义了多个同名方法,但他们参数列表不同,方法重载要求方法:

a、名称相同。

b、参数类型、参数个数、参数顺序至少有一个不同。

方法重载的目的是提供更多的方法选择,方便程序员根据不同的参数类型或个数来调用合适的方法。

所以,从上面方法的重载要求可以看出,返回值不同是不作为方法重载的依据的。

考点分许:

为什么返回值不同不算方法重载的原因有两个:

a、从程序的执行层面来讲:返回值不同如果作为方法重载,那么会产生歧义;

b、从jvm方法签名的角度来讲:返回值并不属于方法签名的那一部分,因此无法定位到具体的调用方法。

什么是方法签名?

方法签名(Method Signature)指的是方法的唯一标识,包括方法的名称、参数列表和参数的顺序。方法签名用于区分不同的方法,以便编译器和虚拟机能够正确识别和调用特定的方法。

①程序执行面

从程序的执行面来讲,如果方法的返回值作为方法重载的依据的话,那么程序的执行就会产生起义,例如以下代码:

public Integer method(){
	return 1111;
}

public String method(){
	return "String";
}

public static void main(String[] args){
	method();
}

此时,我们程序就不知道执行什么代码了。

②JVM方法签名层面

方法签名有两部分组成:

a、方法名称:方法的名称用于标识该方法的功能和用途。

b、参数列表:参数列表指定了方法接受的参数类型和参数顺序,每个参数都包括参数的类型和参数的名称。

JVM是通过方法的签名来定位到要调用的方法的,而在方法签名中并没有返回值,因此返回值并不能作为方法重载的依据。

Comment