Java面向对象编程:参数传递、方法重载解析与引用转换
立即解锁
发布时间: 2025-08-17 02:35:33 阅读量: 2 订阅数: 12 

### Java面向对象编程:参数传递、方法重载解析与引用转换
在Java编程中,参数传递、方法重载解析以及引用转换是面向对象编程的重要概念。下面我们将详细探讨这些内容,并通过具体的代码示例进行说明。
#### 1. 参数传递转换
参数传递转换是Java中一个重要的概念。例如,有如下方法签名:
```java
sendParams(ISafeStack[], StackImpl, ISafeStack, StackImpl[], SafeStackImpl[]);
```
参数传递转换的规则基于参数的引用类型,并且在编译时强制执行。在运行时,形式参数引用的实际对象的类可以通过输出查看,可能是`SafeStackImpl`或`SafeStackImpl[]`。输出中的`[L`字符表示类或接口类型的一维数组。
#### 2. 重载方法解析
重载方法解析是指编译器如何确定在运行时由给定的方法调用将调用哪个重载方法。解析重载方法时,会选择最具体的方法进行执行。如果一个方法可以接受的所有实际参数,另一个方法也能接受,那么前者比后者更具体。如果有多个这样的方法,调用将是模糊的。
例如,有如下重载方法:
```java
private static void flipFlop(String str, int i, Integer iRef) {
out.println(str + " ==> (String, int, Integer)");
}
private static void flipFlop(String str, int i, int j) {
out.println(str + " ==> (String, int, int)");
}
```
以下方法调用是模糊的:
```java
flipFlop("(String, Integer, int)", new Integer(4), 2004);
```
对于这个调用,两个方法都不是更具体的。
编译器解析重载方法的算法包含以下阶段:
1. 首先,在不允许装箱、拆箱或使用可变参数调用的情况下执行重载解析。
2. 如果阶段1失败,则允许装箱和拆箱,但排除使用可变参数调用进行重载解析。
3. 如果阶段2失败,则结合可变参数调用、装箱和拆箱进行重载解析。
下面是一个示例,展示了如何使用上述阶段确定最具体的重载方法:
```java
import static java.lang.System.out;
class OverloadResolution {
public void action(String str) {
String signature = "(String)";
out.println(str + " => " + signature);
}
public void action(String str, int m) {
String signature = "(String, int)";
out.println(str + " => " + signature);
}
public void action(String str, int m, int n) {
String signature = "(String, int, int)";
out.println(str + " => " + signature);
}
public void action(String str, Integer... data) {
String signature = "(String, Integer[])";
out.println(str + " => " + signature);
}
public void action(String str, Number... data) {
String signature = "(String, Number[])";
out.println(str + " => " + signature);
}
public void action(String str, Object... data) {
String signature = "(String, Object[])";
out.println(str + " => " + signature);
}
public static void main(String[] args) {
OverloadResolution ref = new OverloadResolution();
ref.action("(String)");
ref.action("(String, int)", 10);
ref.action("(String, Integer)", new Integer(10));
ref.action("(String, int, byte)", 10, (byte)20);
ref.action("(String, int, int)", 10, 20);
ref.action("(String, int, long)", 10, 20L);
ref.action("(String, int, int, int)", 10, 20, 30);
ref.action("(String, int, double)", 10, 20.0);
ref.action("(String, int, String)", 10, "what?");
ref.action("(String, boolean)", false);
}
}
```
输出结果如下:
```
(String) => (String)
(String, int) => (String, int)
(String, Integer) => (String, int)
(String, int, byte) => (String, int, int)
(String, int, int) => (String, int, int)
(String, int, long) => (String, Number[])
(String, int, int, int) => (String, Integer[])
(String, int, double) => (String, Number[])
(String, int, String) => (String, Object[])
(String, boolean) => (String, Object[])
```
从输出可以看出,编译器优先选择非可变参数调用,并且在选择可变参数调用时,会选择最具体的可变参数类型。
#### 3. 引用类型转换
##### 3.1 强制类型转换运算符
引用类型的强制类型转换表达式具有以下语法:
```
(<destination type>) <reference expression>
```
强制类型转换表达式会检查引用值所引用的对象的类型是否与`<destination type>`兼容,如果不兼容,将抛出`ClassCastException`。`null`字面量可以转换为任何引用类型。
可以应用于强制类型转换运算符操作数的转换包括:
- 引用类型的扩展和缩小转换,可选地后跟未检查的转换。
- 装箱和拆箱转换。
以下代码展示了在强制类型转换过程中可能发生的装箱和拆箱转换:
```java
// (1) 装箱和转换: Number <-- Integer <-- int:
Number num = (Number) 100;
// (2) 转换、装箱、转换: Object <-- Integer <-- int <-- double:
Object obj = (Object) (int) 10.5;
// (3) 转换、拆箱、转换: double <--- int <-- Integer <-- Object:
double d = (double) (Integer) obj;
```
在(1)和(2)中,强制类型转换表达式的结果对象是`Integer`。(1)和(2)中从`int`到`Integer`的装箱转换是隐式的,(3)中从`Integer`到`int`的拆箱转换也是隐式的。
##### 3.2 `instanceof`运算符
二元`instanceof`运算符可用于比较类型,其语法如下:
```
<reference expression> instanceof <destination type>
```
如果左操作数(即`<reference expression>`求值得到的引用值)可以是右操作数(`<destination type>`)的子类型,则`instanceof`运算符返回`true`。如果左操作数为`null`,则始终返回`false`。如果`instanceof`运算符返回`true`,则相应的强制类型转换表达式将始终有效。
`instanceof`运算符和强制类型转换表达式都需要进行编译时检查和运行时检查。编译时检查确定源类型和目标类型之间是否存在子类 - 超类关系。在运行时,`<reference expression>`求值得到一个对象的引用值,实际对象的类型决定了操作的结果。
以下是一个使用`instanceof`运算符的示例:
```java
class Light { /* ... */ }
class TubeLight extends Light { /* ... */ }
class LightBulb extends Light { /* ... */ }
class SpotLightBulb extends LightBulb { /* ... */ }
class NeonLight extends TubeLight { /* ... */ }
public class WhoAmI {
public static void main(String[] args) {
boolean result1, result2, result3, result4, result5;
Light light1 = new LightBulb();
// String str = (String) light1; // (2) 编译时错误。
// result1 = light1 instanceof String; // (3) 编译时错误。
result2 = light1 instanceof TubeLight; // (4) false. 同级类。
// TubeLight tubeLight1 = (TubeLight) light1; // (5) ClassCastException.
result3 = light1 instanceof SpotLightBulb; // (6) false: 超类
// SpotLightBulb spotRef = (SpotLightBulb) light1; // (7) ClassCastException
light1 = new NeonLight();
if (light1 instanceof TubeLight) { // (9) true
TubeLight tubeLight2 = (TubeLight) light1; // (10) OK
// 现在可以使用 tubeLight2 访问 NeonLight 类的对象,但只能访问该对象从 TubeLight 类继承或重写的成员。
}
}
}
```
从这个示例可以看出,`instanceof`运算符有效地确定了左操作数引用的对象的类是否是右操作数指定类型的子类型。在运行时,比较的是引用所表示的实际对象的类型,而不是引用的声明类型。
下面是`instanceof`运算符的更多示例:
```java
interface IStack { /* From Example 7.7 */ }
interface ISafeStack extends IStack { /* From Example 7.7 */ }
class StackImpl implements IStack { /* From Example 7.7 */ }
class SafeStackImpl extends StackImpl implements ISafeStack { /* From Example 7.7 */ }
public class Identification {
public static void main(String[] args) {
Object obj = new Object();
StackImpl stack = new StackImpl(10);
SafeStackImpl safeStack = new SafeStackImpl(5);
IStack iStack;
System.out.println("(1): " + (null instanceof Object)); // Always false.
System.out.println("(2): " + (null instanceof IStack)); // Always false.
System.out.println("(3): " + (stack instanceof Object)); // true: 是 Object 子类的实例。
System.out.println("(4): " + (obj instanceof StackImpl)); // false: Object 不是 StackImpl 的子类型。
System.out.println("(5): " + (stack instanceof StackImpl)); // true: 是 StackImpl 的实例。
System.out.println("(6): " + (obj instanceof IStack)); // false: Object 未实现 IStack。
System.out.println("(7): " + (safeStack instanceof IStack)); // true: SafeStackImpl 实现了 IStack。
o
```
0
0
复制全文
相关推荐










