Java - 2. 面向对象编程
面向对象 - 封装
- 前面我们的思想都是面向过程编程,现在开始学习面向对象编程
- 什么是对象? 对象:一种特殊的数据结构,用来记住一个事物的数据,从而代表该事物
面向对象的快速入门
第一步:设计对象的模板【设计图】:类(类是对象的抽象,用来描述一组对象的共同特征)
- 类中可以定义成员变量、成员方法
- 成员变量:类中定义的变量
- 局部变量:方法中定义的变量
// 这是一个student类
public class Student {// 成员变量:又称对象的属性,用来描述对象的特征String name; // 姓名int age; // 年龄String sex; // 性别int chinese; // 语文成绩int math; // 数学成绩// 成员方法:用来描述对象的行为public void sum(){System.out.println("总分:" + (chinese + math));}public void avg(){System.out.println("平均分:" + (chinese + math) / 2);}
}
第二步:每new一次类就得到一个新对象
public class Test1 {public static void main(String[] args) {Student s1 = new Student(); // 创建Student对象s1.name = "张三";s1.age = 18;s1.sex = "男";s1.chinese = 100;s1.math = 45;System.out.println(s1.name + " " + s1.age + " " + s1.sex);s1.sum(); s1.avg(); Student s2 = new Student(); // 创建Student对象s2.name = "李四"; s2.age = 19;s2.sex = "女";s2.chinese = 87;s2.math = 100;System.out.println(s2.name + " " + s2.age + " " + s2.sex);s2.sum();s2.avg();}
}
类的基本用法 - 构造器
- 构造器是一种特殊方法,名称必须和类名相同
例如:类名为Student,那么定义的构造器必须也为Student
- 构造器的应用场景:创建对象时,同时完成对对象成员变量(属性)的初始化赋值。
// 构造器的特点: // 1. 构造器的名称必须与类名相同 // 2. 构造器不能有返回值类型(包括也不能写void) // 3. 构造器可以重载,可以定义多个 // 4. 创建对象时自动调用构造器 // 5. 类默认自带一个无参构造器,默认调用 // 6. 如果定义了有参构造器,那么默认的无参构造器就没了,若想用无参构造器,就需要自己定义一个无参构造器 public class Student {String name; // 姓名int age; // 年龄char sex; // 性别// 构造器:无参构造器public Student() {System.out.println("无参构造器被调用了!!!");}// 构造器:有参构造器public Student(String n, int a, char s) {System.out.println("有参构造器(完整)被调用了!!!");name = n;age = a;sex = s;}// 构造器:有参构造器public Student(String n){name = n;System.out.println("有参构造器(部分)被调用了!!!");} }
public class Test1 {public static void main(String[] args) {Student s1 = new Student("张三", 18, '男');Student s2 = new Student();Student s3 = new Student("李四");} }// 输出如下: // 有参构造器(完整)被调用了!!! // 无参构造器被调用了!!! // 有参构造器(部分)被调用了!!!
类的基本用法 - this
类的基本用法 - 封装
面向对象编程的3大特征:封装、继承、多态
类就是一种封装
封装的设计思想:合理隐藏、合理暴露
类的基本用法 - Javabean
实体类:一种特殊类。必须满足以下
- 类中成员变量全部私有,并提供public修饰的getter/setter方法
- 类中必须有一个无参构造器。有参构造器可选
// 以下是一个标准的实体类: public class Student {// 封装的思想:将属性私有化(provite),通过方法访问属性// 1.属性私有化。作用:封装属性,避免属性被修改private String name;private int age;private char sex;private double chinese;private double math;// 2.提供getter和setter方法。// set:设置属性值// get:获取属性值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 char getSex() {return sex;}public void setSex(char sex) {this.sex = sex;}public double getChinese() {return chinese;}public void setChinese(double chinese) {this.chinese = chinese;}public double getMath() {return math;}public void setMath(double math) {this.math = math;}// 提供一个无参构造器public Student() {}// 提供一个有参构造器(可选)public Student(String name, int age, char sex, double chinese, double math) {this.name = name;this.age = age;this.sex = sex;this.chinese = chinese;this.math = math;} }
实体类的应用场景:
实体类的对象只负责数据存取,而对数据的业务处理交给其他类的对象来完成,以实现数据和数据业务处理相分离。
类的基本用法 - static
面向对象 - 继承 extends
继承 - 基础
子类能继承父类的 非私有成员(成员变量、成员方法)。
子类对象的创建由子类、父类共同完成。
使用继承的好处:减少重复代码的编写,提高了代码的复用性。
权限修饰符
权限修饰符:用来限制类中的(成员变量、成员方法、构造器…)能被访问的范围。
限制能被访问的范围 | |
private | 本类 |
缺省 | 本类、同一包下的类 |
protected | 本类、同一包下的类、子孙类 |
public | 任意范围 |
继承 - 进阶
Java是单继承的,类不支持多继承,但支持多层继承。
面试题:为什么类不支持多继承? 反证法:假设A类和B类有同名的方法(但功能不同),则会 起冲突
object类:java所有类的祖宗类。任何一个类,都是object的子类或子孙类。
方法重写
当父类的某方法不能满足子类的需求时,子类可以重写一个方法名、参数列表一样的方法,这就是方法重写。
注:重写后,Java会遵循就近原则来访问方法 。
// 方法重写的注意事项
// 1. 重写方法时,加上@Override注解,他可以指定java编译器,检查方法重写的格式是否正确,代码可读性也更好。
// 2. 子类重写父类方法时,访问权限必须大于或等于父类该方法的权限
// 3. 重写方法的返回值类型,要与原方法相同,或范围更小。
// 4. 私有方法、静态方法不能重写,重写会报错。
public class ChongXie02 {public static void main(String[] args) {Dog d1 = new Dog();d1.shout(); // 输出: 汪汪汪!!!}
}class Dog extends Animal{// 重写Animal父类中的 shout 方法@Overridepublic void shout(){System.out.println("汪汪汪!!!");}
}class Animal{// 叫声的方法public void shout(){System.out.println("动物会叫~~");}
}
方法重写 - 拓展:重写object类的tostring方法
public class ChongXie01 {public static void main(String[] args) {Student s1 = new Student("刘思", 18, '女');System.out.println(s1); // 输出:com.HAF.JiCheng.Student@1b6d3586// 直接输出对象时,默认调用OBject父类的toString方法(可以省略不写调用toString的代码),返回对象的地址信息// System.out.println(s1.toString);// 输出对象的地址实际上没有意义,开发中更希望输出对象的内容信息,所以子类要重写0bject的toString方法,}
}class Student {String name;int age;char sex;// 重写toString方法@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", sex=" + sex +'}';}// 生成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 char getSex() {return sex;}public void setSex(char sex) {this.sex = sex;}// 无参构造器public Student() {}// 全参构造器public Student(String name, int age, char sex) {this.name = name;this.age = age;this.sex = sex;}
}
子类中访问其他成员的特点
在子类方法中访问其他成员(成员变量、成员方法):依照就近原则。
- 先子类局部范围找。 然后子类成员范围找。 然后父类成员范围找,仍没有找到则报错。
如果子类和父类,出现重名成员,会优先用子类的,若此时要在子类中使用父类的怎么办?
- 可以通过super关键字,指定访问父类的成员:super.父类成员变量/父类成员方法
public class JiCheng01 {public static void main(String[] args) {Student1 s1 = new Student1();s1.show();}
}class People{String name = "父类";
}class Student1 extends People{String name = "子类";public void show(){String name = "局部变量";System.out.println(name); // 输出:局部变量System.out.println(this.name); // 输出:子类System.out.println(super.name); // 输出:父类// this.name:表示当前对象的成员变量// super.name:表示父类的成员变量}
}
面向对象 - 多态
多态 - 基础
final
final:最终的,不可改变的。可以修饰 类、方法、变量
final 修饰的类:称为最终类 | inal 修饰的方法:称为最终方法 | final 修饰的变量 |
不能被继承 | 不能被重写 | 只能赋值一次 |
- final 修饰基本类型的变量,赋值一次后不可改变。
- final 修饰引用类型的变量,变量存储的地址不能改变,但地址所指向对象的内容可以改变
抽象类 abstract
abstract:抽象。可以修饰 类、方法
- abstract 修饰类:该类称为抽象类。
- abstract 修饰方法:该类称为抽象方法。
抽象类的特点
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。
- 类该有的成员(成员变量、方法、构造器),抽象类也可以有。
- 抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。
- 一个类继承抽象类,必须重写抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
接口
接口 - 基础
1. 以下定义的是一个接口
// 接口:特殊的抽象类,接口内只能定义常量和抽象方法
// 语法:
/* public interface 接口名{常量抽象方法}
*/// 接口不能创建对象,接口是用来被类实现的(也就是被类继承)。实现接口的类称为实现类
// 一个类可以实现多个接口(接口可以理解成干爹),一个接口可以被多个类实现(类可以理解成干儿子)。
// 实现类实现多个接口,必须重写每个接口的所有抽象方法,否则实现类需要定义成抽象类。// 接口的特点:
// 1. 接口不能有构造方法
// 2. 接口不能有成员变量,但可以有常量(默认是public static final)
// 3. 接口中的方法都是抽象方法(默认是public abstract)
// 4. 接口可以继承接口(接口可以理解成干爹),接口可以多继承
// 5. 接口不能有静态代码块和构造代码块// 接口的好处:
// 1. 弥补类单继承的不足,类可以同时实现多个接口。
// 2. 让程序面向接口编程,这样既不用关心实现的细节,也可以灵活方便的切换各种实现。
public interface JieKou01 {// 定义一个常量public static final int TEST_NUM = 10;// 定义一个抽象方法public abstract void test();
}
2. 以下定义的是一个实现类(实现的是上面的接口)
// 实现类:实现接口的类称为实现类
public class JieKou_ShiXianLei implements JieKou01{// 重写接口的所有抽象方法@Overridepublic void test(){System.out.println("重写接口的所有抽象方法");}
}
面向对象 (深入进阶)
内部类
内部类:如果一个类定义在另一个类的内部,这个类就是内部类。