类和对象
Java中使用类class来描述事物,是对一类事物的描述。而对象就是该事物的个体,也称为实例。面对对象编程的重点就是对于类的设计,也即是设计类的成员。
常见的类的成员有属性和行为,属性就是类中的成员变量,行为就是对应类中的成员方法。例如一个Person类,他有年龄、性别、邮箱…等基本属性,这些基本属性称之为类的属性(姓名、年龄、性别);这个Person类还有很多技能(例如吃饭、睡觉等),这称之为这个类的行为。
public class Person {
// 属性:定义这个Person类的属性(姓名、年龄、性别)
String name;
int age;
String gender;
// 行为:定义Person类的行为(吃饭、睡觉)
public void eating() {
System.out.println("Person的吃饭方法");
}
public void sleeping() {
System.out.println("Person的睡觉方法");
}
public static void main(String[] args) {
// New一个Person对象,并命名为p1,调用这个类的两个方法
Person p1 = new Person();
p1.eating();
p1.sleeping();
}
}
输出的界面为:
类的成员:属性
1、定义属性的方法 :数据类型 变量名 = 变量值
2、属性需要先声明(声明在类的一对{}中),后使用
3、声明时可以用权限修饰进行修饰分别为private、public、缺省、protected
上述例子中的属性没有写具体的权限修饰符,就是默认为缺省的权限。
类的成员:方法
方法的声明: 权限修饰符 返回值类型 方法名(形参列表){方法体}
权限修饰符: 这里也涉及到了面向对象的一大特征:封装和隐藏
作用域范围
- private: 类内部
- 缺省:类内部,同一个包(不写默认就是缺省)
- protected:类内部,同一个包,不同包的子类,同一个工程。
- 当我们创建一个类的对象之后,我们可以通过 对象.属性的这个方式对属性进行赋值,但是对于有权限修饰符的属性就会受到制约,为了防止用户直接使用 对象.属性 这个方式对属性进行赋值,一般将对象属性的权限修饰符设置为private,这样可以避免上述情况。这样也并不是无法对内容进行修改和获取,可以对于private的属性设置一个public的方法getxxx()和setxxx(),从而实现对于属性的封装。
具体操作如下:
// 定义类的属性为私有属性private
private String name;
private int age;
private String gender;
// 设置私有属性的get和set方法,便于在类的外部对类的属性进行修改和获取
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
这里就对于Person类的三个属性设置了get和set方法这样就可以在Person类的外部操作Person类内部的值。
返回值类型: 如果方法具有返回值,需要在申明方法的时候指定返回值的类型,方法体中使用return关键字进行返回。
方法名:自定义,可以命名为吃饭、睡觉等…
注意:方法体中不能定义其他方法。
构造器的使用
构造器最大的作用就是在创建一个新的对象的时候,系统会对这个对象的实例进行默认的初始化,如果想更改这种默认值,可以通过自定义构造器来实现。如果自定义的带参数的构造器,就是用你传入构造器的参数对对象的实例进行初始化。
1、构造器的作用:
- 创建对象
- 初始化对象的属性
2、构造器的说明
- 如果没有定义构造器的话,每一个类会默认提供一个空参的构造器
- 定义构造器的格式 权限修饰符 类名(形参列表) { }
- 一个类中可以定义多个构造器,彼此构成重载,但是在自定义了一个有参构造器装之后,系统默认提供的无参构造器就会被取消,这时候如果需要使用使用无参构造器,就需要手动定义一个无参构造器。
3、this关键字的使用
this可以理解为正在创建的对象,在一个类中,我们可以使用this.属性和this.方法创建对象的属性和方法。一般情况下会省略this.,但是对于方法的形参和类的属性重名的情况就需要显示的使用“this.”的方法,这样可以表示我们使用的变量名是属性,而不是形参。
this还可以实现调用构造器
- 在写类的构造时,可以显示的使用“this.(形参)”的方式,调用本类中重载的其它构造器
- “this.(形参)”必须写在构造器的首航,而且每一个构造器中最多只能申明一个 “this.(形参)”
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.eating();
p1.sleeping();
p1.setAge(15);
System.out.println(p1.getAge());
}
}
class Person {
// 属性:定义这个Person类的属性(姓名、年龄、性别)
private String name;
private int age;
private String gender;
// 构造器
// 默认每一个类都拥有的空构造器,就算你不写也可以使用,但是你如果自定义了其他构造器
// 就不能使用这个空参构造器,除非再手动定义一个空参构造器
public Person() {} // 这个就是自定义的空属性构造器
// 自定义初始值的构造器
public Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
// 行为:定义Person类的行为(吃饭、睡觉)
public void eating() {
System.out.println("Person的吃饭方法");
}
public void sleeping() {
System.out.println("Person的睡觉方法");
}
// 属性的get、set方法
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
public String getGender() {return gender;}
public void setGender(String gender) {this.gender = gender;}
}
继承
因为有很多类有相同的属性和方法,将这些相同的属性和方法放到一个类中,这样很多类可以通过继承这个类,不需要重复的定义相同的属性和方法,这样减少了代码的冗余,也便于进行功能的扩展。
继承的格式
class A extends B{}
A:子类、派生类
B:父类、超类、基类
继承的特点
- 子类一旦继承了父类,就拥有了父类的所有属性和方法,就算父类中的属性使用的是private时,子类也继承了这个属性,只不过由于封装新的影响,子类并不能直接调用父类中的属性,需要使用public的方法函数来实现修改和调用。
- 子类在继承父类之后,还可以申明自己特有的属性和方法,实现功能扩展。
- 所有的类都继承于一个父类java.lang.Object 类
package test1;
/**
* @Description: 父类Person类
* @Author: cy
* @date: 2022/8/13 13:59
**/
public class Person {
// 属性:定义这个Person类的属性(姓名、年龄、性别)
private String name;
private int age;
private String gender;
// 构造器
// 默认每一个类都拥有的空构造器,就算你不写也可以使用,但是你如果自定义了其他构造器
// 就不能使用这个空参构造器,除非再手动定义一个空参构造器
public Person() {} // 这个就是自定义的空属性构造器
// 自定义初始值的构造器
public Person(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
// 行为:定义Person类的行为(吃饭、睡觉)
public void eating() {
System.out.println("Person的吃饭方法");
}
public void sleeping() {
System.out.println("Person的睡觉方法");
}
// 属性的get、set方法
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
public String getGender() {return gender;}
public void setGender(String gender) {this.gender = gender;}
}
package test1;
/**
* @Description: 继承练习,子类Student,继承于Person类
* @Author: cy
* @date: 2022/8/14 14:20
**/
public class Student extends Person{
String skil;
public void study() {
System.out.println("正在学习");
}
}
package test1;
/**
* @Description: 继承的测试类
* @Author: cy
* @date: 2022/8/14 14:21
**/
public class ExtendsTest {
public static void main(String[] args) {
Person p1 = new Person();
System.out.print("Person类:");
p1.eating();
Student p2 = new Student();
System.out.print("Student类:");
p2.eating();
p2.setName("学生类");
System.out.println(p2.getName());
}
}
输出结果如下所示:
方法的重写
子类继承父类以后,可以对父类中的方法进行覆盖操作。
- 方法重写的格式
方法的声明:权限修饰符 返回值类型 方法名(形参列表){方法体}
子类重写的方法的方法名和形参列表必须和父类被重写的方法的方法名、形参列表相同
子类的访问权限不能小于父类方法的访问权限。
返回值类型:如果父类返回值是void 那子类的方法只能是void;如果是基本数据类型,则子类也必须是基本数据类型;如果是A类型,则子类的返回值类型必须为A类型或者A类型的子类。
多态性
父类的引用指向子类的对象
等式左边是父类的引用(这里的父类其实并不具备子类中某个特有的方法的功能),等式右边是子类的对象(实际运行是是子类在重写父类的方法)
对于多态只有在方法调用的那一刻,才会决定需要调用的具体方法,这种情况也称之为晚绑定或者静态绑定。
上述的情况只适用于方法,那如果父类想要使用子类中的所有属性和方法,这时候就需要用到强制类型转换,也称之为向下转型
子类 子类对象名 = (子类) 父类对象名
package test2;
/**
* @Description: Person类
* @Author: cy
* @date: 2022/8/14 14:34
**/
public class Person {
String name;
public void eating() {
System.out.println("Person正在吃饭");
}
}
package test2;
/**
* @Description: 子类,继承父类Person
* @Author: cy
* @date: 2022/8/14 14:35
**/
public class Man extends Person{
public void eating() {
System.out.println("Man正在吃饭");
}
public void drinking() {
System.out.println("Man正在喝饮料");
}
}
package test2;
/**
* @Description: 测试多态性
* @Author: cy
* @date: 2022/8/14 14:37
**/
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.eating();
Man m1 = new Man();
m1.eating();
// 对象的多态性,父类的引用指向子类的对象
Person p2 = new Man();
// 多态的使用:当调用子父类同名同参数方法时,实际调用的是子类重写父类的方法---虚拟方法调用
p2.eating();
}
}
输出结果: