面向对象基础+进阶1
一、构造器
在创建人类的对象时,是先把一个对象创建好后,再给他的年龄和姓名属性赋值,如果现在要求在创建人类的对象时,就直接指定这个对象的年龄和姓名,这时就可以使用构造器。它的主要作用是完成对新对象的初始化。
主要特点:
- 构造器的修饰符可以默认,也可以是 public protected private
- 构造器没有返回值
- 方法名和类名字必须一样
- 参数列表和成员方法一样的规则
- 构造器的调用, 由系统完成
[修饰符]方法名(形参列表){
方法体;
}
构造器可以具有参数,这些参数用于接收创建对象时传递的值,以便在初始化对象时使用。构造器的主要任务是为对象分配内存空间并初始化其成员变量。
示例:
public class Car {
private String make;
private String model;
private int year;
// 构造器
public Car(String make, String model, int year) {
this.make = make;
this.model = model;
this.year = year;
}
public String getMake() {
return make;
}
public void setMake(String make) {
this.make = make;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
}
Car类具有一个带有参数的构造器,用于接收汽车的品牌、型号和年份。构造器内部使用this关键字来引用对象的成员变量,以区分构造器参数和成员变量。
使用构造器创建Car对象并初始化其属性:
Car car = new Car("BMW", "740Li", 2022);
System.out.println(car.getMake());
通过构造器,可以方便地在创建对象时为其提供初始值,确保对象的正确初始化,并且可以在构造器中执行其他必要的操作,如参数验证、对象依赖的注入等。
注意事项:
● 通过构造器创建对象(实例)
● 构造器是用于初始化实例的一组指令
● 在构造方法执行之后才完成对象的创建
● 可以向构造器传递参数
● 构造器的名称必须与类名一致
● 修饰符只有访问控制修饰符
● 构造器不能定义返回值
● 类可以定义多个构造器,至少有一个构造器
● 如果类中未编写任何构造器,则会包含一个默认的构造器
● 添加任何构造器都会失去默认构造器
详细理解:
-
通过构造器创建对象(实例):
构造器在Java中用于创建对象(实例)。使用new
关键字和构造器来创建对象,例如:Car car = new Car();
。这条语句调用Car
类的构造器来创建一个新的Car
对象。 -
构造器是用于初始化实例的一组指令:
构造器是一个特殊的方法,它包含一组指令,构造器在对象创建时自动调用,并在对象使用之前对其进行必要的设置和准备工作。 -
在构造方法执行之后才完成对象的创建:
对象的创建过程包括分配内存空间和初始化成员变量。构造器的执行是在对象创建过程中的一部分,只有在构造器执行完毕后,对象才算完全创建。 -
可以向构造器传递参数:
构造器可以接受参数,这些参数用于在创建对象时传递值,并在构造器内部使用这些值进行初始化。通过向构造器传递参数,可以在创建对象时提供初始值,使对象具有特定的属性。 -
构造器的名称必须与类名一致:
构造器的名称必须与所属类的名称完全相同。这是因为构造器用于创建对象,因此与类名保持一致有助于标识构造器与其所属类之间的关联。 -
修饰符只有访问控制修饰符:
构造器可以具有访问控制修饰符,例如public
、private
、protected
和默认(无修饰符)。这些修饰符决定了构造器的可访问性。 -
构造器不能定义返回值:
与其他方法不同,构造器没有返回类型,包括void
。这是因为构造器的主要目的是创建对象,而不是返回任何值。 -
类可以定义多个构造器,至少有一个构造器:
一个类可以定义多个构造器,每个构造器可以有不同的参数列表。这允许在创建对象时使用不同的方式和参数进行初始化。至少有一个构造器是必需的,如果没有显式定义构造器,会有一个默认的无参构造器。 -
如果类中未编写任何构造器,则会包含一个默认的构造器:
如果在类中没有显式定义任何构造器,Java编译器会为该类提供一个默认的构造器。默认构造器没有参数,并执行一些默认的操作(如对成员变量的初始化)。 -
添加任何构造器都会失去默认构造器:
如果在类中显式定义了至少一个构造器,而没有提供默认的无参构造器,那么默认的无参构造器就不再可用。因此,如果希望继续使用默认构造器,需要显式地定义一个没有参数的构造器。
二、静态成员和实力成员
在Java中,成员变量和方法可以分为静态成员和实例成员两种类型。
- 静态成员
- 静态成员属于类本身,而不是类的实例。
- 静态成员只有一份拷贝,在类加载时初始化,并且在整个程序执行过程中保持不变。
- 可以通过类名直接访问静态成员,无需创建类的实例。
- 静态成员可以在任何地方被访问,无论是静态方法、实例方法还是其他类。
- 通常用于表示与类相关的共享数据或提供对类级别操作的方法。
示例:PI是一个静态常量,add()方法是一个静态方法,用于对两个整数进行相加。
public class MathUtils {
public static final double PI = 3.14159;
public static int add(int a, int b) {
return a + b;
}
}
实例成员
- 实例成员属于类的实例,每个实例都有自己的一份。
- 实例成员在创建对象时分配内存,并且可以具有不同的值。
- 实例成员需要通过类的实例来访问。
- 实例成员只能在已创建对象的上下文中使用。
- 可以用于表示对象的特定属性和提供对象级别的操作。
示例: name是一个实例变量,用于表示人的姓名,setName()和getName()方法是实例方法,用于设置和获取姓名。
public class Person {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
三、父类子类类型转换
Java中的子类和父类相互转换时,涉及向上转型和向下转型。这两个转换允许在继承层次结构中的不同类之间进行转换。
- 设有一个父类Animal和一个子类Dog:
class Animal {
public void eat() {
System.out.println("Animal() eat");
}
}
class Dog extends Animal {
public void wangwang() {
System.out.println("Dog() wangwang");
}
}
- 向上转型(Upcasting)
向上转型是指将子类的对象赋值给父类的引用变量。这是一种隐式的转换,因为子类对象具有父类的所有属性和行为。
Animal animal = new Dog(); // Upcasting
在上面的例子中,创建了一个Dog对象,并将其赋值给Animal类型的引用变量animal。尽管animal是一个Animal引用,但它指向的实际对象是Dog类型的。
这意味着我们可以通过animal引用调用Animal类中的方法,以及在Dog类中定义的bark()方法。
Animal animal = new Cat(); // 定义一个动物是猫
- 向下转型(Downcasting)
向下转型是指将父类的引用变量转换为子类类型。这是一种显式的转换,并且需要在转换之前使用类型转换操作符。
if (animal instanceof Dog) { // 检查通过后
Dog dog = (Dog) animal;
dog.wangwang();
} else {
System.out.println("转型失败");
}
在上面的代码中,首先进行了向上转型,然后使用instanceof操作符检查animal引用是否是Dog类的实例。如果是,就可以进行向下转型并访问Dog类的方法。
在进行向下转型之前,应始终使用instanceof进行类型检查,以确保在转换过程中不会发生ClassCastException异常。
注意事项
在使用子类和父类相互转换时,需要注意以下几点:
向上转型是隐式的,无需显式转换。子类对象可以直接赋给父类引用。(狗可以直接转为动物,不会出错)
向下转型是显式的,需要使用类型转换操作符。在进行向下转型之前,应始终使用instanceof进行类型检查,以确保转换的安全性。(动物不能转换为狗,还可以是其他)
如果尝试对一个不是子类对象的父类引用进行向下转型,会导致ClassCastException异常。
可以通过向上转型和向下转型实现对象的多态性,即在父类引用的基础上调用子类特有的方法。
在进行向下转型之前使用instanceof
进行类型检查是为了确保转换的安全性。这是因为在继承层次结构中,父类引用可以指向子类对象,但是子类引用不能直接指向父类对象。如果我们尝试将一个不是子类对象的父类引用进行向下转型,会导致编译错误或运行时异常。