面向对象三大特性(封装、继承、多态)
封装
使用private修饰符对属性进行修饰,限制属性的访方问权限,只有类内部能够访问这样的属性,其它的类通过对象属性的方式是无法访问的。从而对对象的状态(数据)进行保护,外部类要访问的话需要通过调用gt/Set的方法,保证属性统一访问。
-
学生类Student
有一些属性都是用private修饰
提供set,get方法访问这些属性,在调用set的时候可以限制赋值的内容,在调用get的时候可以返回指定的数据,转换和限制的逻辑封装在类的方法中
//private 就是私有修饰符 private String name; private int sex; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { String result = sex == 1 ? "男" : "女"; return result; } public void setSex(int sex) { //限制属性的范围,不能随便赋值 if (sex < 0 || sex > 1){ throw new RuntimeException("性别只能为0和1"); } this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }
-
使用学生类
使用学生类时不能直接访问属性必须通过get、set方法
如果给属性赋值,不符合要求(比如性别就不能设置0和1以外的值),就报异常
用get方法读取属性,会读取到学生类中转换之后的内容(比如这里的男,女)Student student = new Student(); //student.name = "张三"; //私有成员变量,不能直接用对象.属性方式访问 student.setName("张三"); student.setSex(1); student.setAge(11); System.out.println(student.getSex());
访问修饰符
控制访问权限的关键字称为访问修饰符,有private、default、protected、public
访问修饰符可以用在类,成员变量以及方法前面
局部变量不需要访问修饰符
访问修饰符访问权限大小排序
private < default < protected < public
同类 | 同一个包 | 子类 | 其他类 | |
---|---|---|---|---|
private(私有的) | √ | × | × | × |
default(默认的)(不写修饰符) | √ | √ | × | × |
protected(受保护的) | √ | √ | √ | × |
public(公有的) | √ | √ | √ | √ |
继承
A类可以通过extends关键字继承B类,继承之后A类可以有有一些B类中的属性或方法,实现代码重复利用
语法:
[修饰符] class 子类 extends 父类{
}
子类也叫派生类,衍生类,subClass
父类也叫基类,超类,superClass
- 继承的特点
继承只能是单继承,只能有一个父类;一个父类可以有多个子类
继承可以多重继承,A继承B,B继承C
Opject是所有类的父类(所有的类都继承Opject类)
子类可以重写(覆盖)父类的方法
创建子类时,会先执行父类的构造方法
代码案例
父类定义了一个成员变量name,一个方法area( )
子类Retangle继承了父类Shap,Retangle自动有name属性和area( )方法
子类中定义自己的属性,也可以写自己的方法,还以重写父类继承来的方法
-
父类Shap
public class Shap { public String name; public void area (){ System.out.println("显示图形的面积"); } }
-
子类Retangle
public class Retangle extends Shap{ private float width;//矩形的宽度 private float hight;//矩形的高度 public Retangle() { this.name = "矩形"; } //构造方法 public Retangle(float width, float hight) { this();//调用无参的构造方法,在构造方法中调用其他构造方法,要写在第一行 this.width = width; this.hight = hight; } @Override //重写,覆盖父类的方法 public void area() { float area = width * hight; System.out.println(area); } }
测试代码
public class RetangleTest {
public static void main(String[] args) {
Retangle retangle = new Retangle(5,3);
retangle.area();
System.out.println(retangle.name);
}
}
重写override(覆盖)
子类继承父类时,子类对父类的方法代码重新写过,就叫重写
重写的特性:
- 方法名、参数列表(个数、类型、顺序)、返回值必须一致
- 访问的权限(修饰符)不能比父类更小(跟父类的访问权限一致或比父类大)
- 比如 父类的修饰符是 protected 子类的修饰符不能是 private
- 如果要抛出异常,不能比父类的异常更大
public void test(String str,int i)
public void test(String a,int d)
重载overload
在一个类中(不一定要继承),如果有多个方法的方法名相同,参数列表不同(个数、类型、顺序),这些同名的方法就称为重载
重载的特性:
- 方法名相同
- 参数列表不同(个数、类型、顺序)
public class Rect {
/**
* 计算正方形的面积
*/
public void area(int width){
System.out.println(width * width);
}
/**
* 计算长方形的面积
* @param widht
* @param hight
*/
public void area(int widht ,int hight){
System.out.println(widht * hight);
}
}
构造方法的特点
-
构造方法没有返回值,而不是返回值是void
-
构造方法的方法名和类名是一致的
-
构造方法的目的就是实例化对象(将类进行实例化,创建存放对象的空间)
-
构造方法可以通过new进行调用
-
一个类里面存在默认的构造方法(无参数),当这个类里面存在他的重构方法,那么默认的无参构造就会消失
相关面试题
-
构造方法被调用的时候一定会创建对象?
错误。子类的构造方法执行时,要先调用父类的构造方法,这时候父类并没有创建出对象
-
重写和重载的区别?
-
构造方法能重载吗?能重写吗?
可以重载(一个类可以有多个不同参数的构造方法)
不可以重写
this和super关键字
这两个关键字都可以指代对象或者方法
-
当对象用
public Shap() { //this用在构造方法中,代表当前对象 this.name = "形状"; System.out.println(this.name); } public void setAge(int age) { //this用在用在set方法中,代表当前对象 //为了区分成员变量和局部变量,因为两个都叫age this.age = age; } public void parentArea(){ super.area(); }
-
当成构造方法使用
- 构造方法中调用构造方法,用this代替构造方法名
- 构造方法中调用构造方法,调用语句只能放在第一行
- 子类要调用父类的构造方法,用super()
- 如果子类的构造方法没有调用父类的构造方法,默认调用父类无参的构造方法
- 如果父类没有无参的构造方法,在子类的构造方法中必须要调用父类有参的构造方法
Parent.java
public class Parent {
private int age;
private String name;
private int sex;
public Parent(){
System.out.println("无参");
}
public Parent(int age, String name) {
this();
this.age = age;
this.name = name;
System.out.println("两个参数");
}
public Parent(int age, String name, int sex) {
this(sex, name);
this.sex = sex;
System.out.println("三个参数");
}
public static void main(String[] args) {
Parent parent = new Parent(22,"张三",1);
}
}
Son.java
public class Son extends Parent{
private int age;
private String name;
private int sex;
public Son() {
super();//执行父类的构造方法,不写也会自动调用
System.out.println("son 无参");
}
public Son(String name, int sex) {
this.name = name;
this.sex = sex;
System.out.println("两个参数");
}
public Son(int age, String name, int sex) {
this.age = age;
this.name = name;
this.sex = sex;
System.out.println("三个参数");
}
public static void main(String[] args) {
Son son = new Son();
new Son(22,"赵四",0);
}
}
多态
一个类在编译时和运行时同一个方法呈现出不同状态
比如:动物有一个发出叫声的方法,他的子类有猫类,猫的叫声为喵喵喵;还有一个子类是狗,狗的叫声是汪汪汪
现在有有一个动物类的对象,调用发出叫声的方法,有可能是:喵喵喵,也有可能是:汪汪汪
形成多态的条件 :
- 有继承关系,子类重写父类的方法
- 父类类型定义的变量,用子类的实例给他赋值
多态的用处:
统一管理,无限适配或扩展
例如:Windows操作系统中有打印功能,规定好方法,不同类型的打印机(针式、喷墨、激光、彩色、黑白)只要继承和适配答应方法,就可以实现自动打印适配所有的打印机
Animal.java
public class Animal {
public void shout(){
System.out.println("动物在叫");
}
}
Cat.java
public class Cat extends Animal{
@Override
public void shout() {
System.out.println("喵喵喵");
}
}
Dog.java
public class Dog extends Animal{
@Override
public void shout() {
System.out.println("汪汪汪");
}
}
测试代码
public class AnimalTest {
public static void main(String[] args) {
Animal animal1 = new Animal();
animal1.shout();
Cat cat = new Cat();
cat.shout();
Dog dog = new Dog();
dog.shout();
System.out.println("=====Animal animalCat = cat=======");
Animal animalCat = cat;
animalCat.shout();
System.out.println("=====Animal animalDog = dog=======");
Animal animalDog = dog;
animalDog.shout();
}
}
向上造型 (安全的)
父类 变量 = new 子类( )
父类定义的变量,用子类的实例对象赋值
**注意:**向上造型时,不能调用子类自己定义的方法
System.out.println("=====Animal animalCat = cat=======");
Animal animalCat = cat;
animalCat.shout();
System.out.println("=====Animal animalDog = dog=======");
Animal animalDog = dog;
animalDog.shout();
向下造型 (有条件的)
子类 变量 = (子类) 父类的对象
用父类的对象给子类变量赋值,向下造型必须使用强制类型转换
向下造型分以下几种情况
- 直接new一个父类对象赋给子类变量,不允许,运行时会抛异异常
- 父类对象是通过子类对象向上造型上去的实例,这种对象可以向下造型,也要强制转换,子类的所有方法都可以使用
- 跟2一样的做法,但是换了子类,如猫的子类对象,向下造型成狗,不允许,运行时会抛异常
//向下造型
//1.直接用父类创建的对象赋给子类变量,会抛异常
// Cat cat = (Cat) new Animal();
//把通过向上造型得到的父类对象赋给子类对象,可以调用继承至父类的方法,也可以子类自己的方法
Animal animal1 = new Cat();
System.out.println("=====向下造型=======");
Cat cat1 = (Cat) animal1;
cat1.shout();
cat1.eat();
System.out.println("=====向下造型换了子类的对象=====");
Animal animal2 = new Dog();
Cat cat2=(Cat)animal2;//会抛出异常