目录
21、toString
在Java中,
toString()
方法是Object
类中的一个方法,因此它可以被所有类继承和使用。toString()
方法返回一个代表对象的字符串表示形式。当您打印一个对象或将其转换为字符串时,Java会自动调用该对象的
toString()
方法。默认情况下,Object
类的toString()
方法返回包含类名和哈希码的字符串表示。例如,com.example.MyClass@1234567
。然而,通常情况下,我们会根据具体类的属性和行为,重写
toString()
方法,以便返回更有意义的字符串表示形式。这通常在自定义类中是很常见的做法。以下是一个示例,展示如何在自定义类中重写
toString()
方法:
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 重写toString()方法
@Override
public String toString() {
return "Person[name=" + name + ", age=" + age + "]";
}
public static void main(String[] args) {
Person person = new Person("John", 25);
System.out.println(person.toString()); // 调用toString()方法
// 或者直接打印对象,会自动调用toString()方法
System.out.println(person);
}
}
在上述示例中,
Person
类重写了toString()
方法来返回Person
对象的名称和年龄。当我们调用toString()
方法时,它会返回一个形如Person[name=John, age=25]
的字符串。该字符串提供了更具描述性的对象表示形式。请注意,重写
toString()
方法是一种良好的实践,可以方便地调试和输出对象的状态信息。这对于在日志中记录对象信息或与其他开发人员共享对象数据时非常有用。需要注意的是,当使用
System.out.println()
打印对象时,它会自动调用对象的toString()
方法。因此,可以直接使用System.out.println(object)
来打印对象的字符串表示形式,而不需要显式调用toString()
方法。
22、instanceof
在Java中,
instanceof
是一个二元运算符,用于检查对象是否为特定类的实例或特定接口的实现。
instanceof
的语法是:对象 instanceof 类名
或者对象 instanceof 接口名
它会返回一个布尔值,表示对象是否是该类的实例或接口的实现。
以下是一个示例:
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
public class Main {
public static void main(String[] args) {
Animal animal = new Dog();
System.out.println(animal instanceof Animal); // true
System.out.println(animal instanceof Dog); // true
System.out.println(animal instanceof Cat); // false
Dog dog = new Dog();
System.out.println(dog instanceof Animal); // true
System.out.println(dog instanceof Dog); // true
System.out.println(dog instanceof Cat); // false
Animal animal2 = new Cat();
System.out.println(animal2 instanceof Animal); // true
System.out.println(animal2 instanceof Dog); // false
System.out.println(animal2 instanceof Cat); // true
}
}
在上述示例中,我们创建了一个
Animal
类和两个子类Dog
和Cat
。通过使用instanceof
运算符,我们可以检查对象的类型。
animal instanceof Animal
返回true
,因为animal
是Animal
类的实例。animal instanceof Dog
返回true
,因为animal
是Dog
类的实例(尽管它的声明类型是Animal
)。animal instanceof Cat
返回false
,因为animal
不是Cat
类的实例。dog instanceof Animal
返回true
,因为dog
是Animal
类的实例。dog instanceof Dog
返回true
,因为dog
是Dog
类的实例。dog instanceof Cat
返回false
,因为dog
不是Cat
类的实例。animal2 instanceof Animal
和animal instanceof Dog
同样返回true
和false
,因为animal2
的实际类型是Cat
。
instanceof
运算符在许多场景中很有用,例如在使用继承和多态的情况下,可以通过检查对象的类型来决定如何处理对象。
23、参数传递的问题
在Java中,参数传递可以是按值传递(pass-by-value)或按引用传递(pass-by-reference)的。
按值传递(Pass-by-value):
当使用按值传递时,方法接收到的是实际参数的一个副本,而不是原始参数本身。这意味着对参数值的修改不会影响原始变量的值。Java基本类型(如int
、double
、boolean
等)以及不可变对象(如String
)都是按值传递的。示例代码如下:
public class Main {
public static void main(String[] args) {
int num = 10;
System.out.println("Before: " + num); // 输出 "Before: 10"
changeValue(num);
System.out.println("After: " + num); // 输出 "After: 10"
}
public static void changeValue(int value) {
value = 20;
}
}
在上述示例中,
changeValue
方法接收一个int
类型的参数,并将其值修改为20。但是,这并不影响main
方法中原始的num
变量,因为它是通过值传递实参的副本传递给changeValue
方法。按引用传递(Pass-by-reference):
在Java中,对于对象类型的参数,实际上是按引用传递的。也就是说,方法接收的是实参的引用,方法内部对参数的修改会影响原始的对象。这是因为对象类型的变量存储的是一个引用,指向实际对象的内存地址。示例代码如下:
public class Main {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Hello");
System.out.println("Before: " + sb); // 输出 "Before: Hello"
changeValue(sb);
System.out.println("After: " + sb); // 输出 "After: World"
}
public static void changeValue(StringBuilder str) {
str.append(" World");
}
}
在上述示例中,
changeValue
方法接收一个StringBuilder
对象作为参数,并在该对象上执行了修改操作。由于对象是按引用传递的,因此在changeValue
方法中对str
对象的修改会影响main
方法中的原始sb
对象。需要注意的是,虽然对象是按引用传递的,但是不可以直接修改对象的引用本身。例如,无法在方法中将传递的对象指向另一个对象。这是因为方法接收到的是引用的拷贝,修改引用本身并不会影响原始的引用。
总结起来,Java中的参数传递是按值传递的,基本类型和不可变对象被复制,而对象类型则是传递引用的副本。这样的理解可以帮助我们正确理解方法调用中参数的传递方式。
24、向上转型,向下转型
在Java中,向上转型(Upcasting)和向下转型(Downcasting)是用来处理对象的多态性的概念。
向上转型:
向上转型是指将子类对象赋值给父类引用变量。这种转型是自动的,无需显式转换。示例代码:
class Animal {}
class Dog extends Animal {}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
Animal animal = dog; // 向上转型
}
}
在上述示例中,
Dog
类继承自Animal
类。我们创建了一个Dog
对象,并将其赋值给Animal
类型的变量animal
。这是向上转型的示例。通过向上转型,我们可以将子类对象视为父类对象,以便在多态的场景中访问共享的父类成员。向下转型:
向下转型是指将父类对象转换为子类对象。这种转型需要显式转换,并且在转换之前需要进行类型检查,以避免ClassCastException
异常。示例代码:
class Animal {}
class Dog extends Animal {}
public class Main {
public static void main(String[] args) {
Animal animal = new Dog();
Dog dog = (Dog) animal; // 向下转型
}
}
在上述示例中,我们创建了一个
Dog
对象,并将其向上转型为Animal
类型的引用。然后,我们将animal
变量向下转型为Dog
类型的变量dog
。这是向下转型的示例。通过向下转型,我们可以恢复父类对象为子类对象,以便访问子类特有的成员和方法。需要注意的是,向下转型存在风险,因为在运行时无法确定父类对象实际引用的是哪个子类对象。如果尝试将一个不正确的类型向下转型为子类类型,会导致
ClassCastException
异常。因此,在进行向下转型之前,我们应该先使用instanceof
操作符进行类型检查,以确保转型的安全性。示例代码:
Animal animal = new Animal();
if (animal instanceof Dog) {
Dog dog = (Dog) animal; // 向下转型
} else {
System.out.println("animal不是Dog类型");
}
总结:
- 向上转型是将子类对象赋值给父类引用变量,是自动的、隐式的转换。
- 向下转型是将父类对象转换为子类对象,需要显式转换,并且在转换之前需要进行类型检查。
- 向下转型存在风险,应该先使用
instanceof
操作符进行类型检查,以确保转型的安全性。