Java面向对象03:三大特性
封装
属性私有,get/set
- 程序设计追求”高内聚,低耦合“:高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合就是仅暴露少量的方法给外部使用
- 通常,应禁止直接访问一个对象的属性,而应通过操作接口来访问,这称为信息隐藏
/*
1. 提高程序的安全性,保护数据
2. 隐藏代码的实现细节
3. 统一接口
4. 增强系统可维护性
*/
public class Hello {
public static void main(String[] args) {
Student xm = new Student();
// xm.name = "小明"; //name属性是privat私有类型,因此对象不能直接通过属性名调用
xm.setName("小明"); //只能通过set方法进行赋值
System.out.println(xm.getName()); //只能通过get方法获取值
xm.setGender('男');
System.out.println(xm.getGender());
}
}
class Student{
private String name;
private char gender;
public String getName() { //定义私有属性专用的赋值和调用方法,快捷键alt + insert
return name;
}
public void setName(String name) {
this.name = name;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
if (gender == '男' | gender == '女'){ //私有属性的set方法可以定义一些规则,避免不合法的信息输入
this.gender = gender;
}
else{
this.gender = '无';
}
}
}
继承
继承的本质是对某一批类的抽象,是类与类之间的一种关系,子类扩展父类,使用关键字extends表示
Java中类只有单继承,没有多继承,且被final修饰的类不可被继承。所有类都直接或间接继承Object类
/*
四种修饰符:
1. public,需要被继承时使用
2. private,一般私有属性会用到
3. protected
4. default,默认不写
*/
public class Father {
public static void main(String[] args) {
Son xm = new Son();
//父类的say()方法子类对象可以直接调用
xm.say();
// xm.money; //父类的私有属性,子类无法直接继承
//私有属性通过get方法调用
System.out.println(xm.getMoney());
}
private int money = 1;
public int getMoney() {
return money;
}
public void say() {
System.out.println("可以说话");
}
}
class Son extends Father{
//子类继承父类的所有方法
}
super关键字
public class Hello {
public static void main(String[] args) {
Son son = new Son();
son.method("ty");
}
}
class Father {
Father(){
System.out.println("父类的无参构造方法");
}
Father(String name){
System.out.println("父类的有参构造方法");
}
protected String name = "tyy";
}
class Son extends Father {
Son (){
// super(); //默认先隐式调用父类的无参构造方法,再执行子类的构造方法
System.out.println("子类的无参构造方法");
// super(name); //如果父类没有无参构造方法,则必须在子类显式调用父类的有参构造方法,且必须写在第一行,否则报错。但子类的构造方法也要放在第一行,产生了冲突。因此就算不需要无参构造器,也要写出来
}
protected String name = "tty";
public void method(String name){
System.out.println(name); //ty
System.out.println(this.name); //tty,this关键字特指本类的属性
System.out.println(super.name); //tyy,如果子类和父类的属性或方法重名,则通过super关键字来特指父类的
}
}
方法重写
重写的前提是有继承关系,重写的目的就是实现多态,让子类能拓展父类的功能
- 只能重写父类的非静态、非常量、非私有方法
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大但不能缩小(private --> default --> protected --> public)
- 抛出的异常:范围可以缩小但不能扩大
public class Hello {
public static void main(String[] args) {
//父类引用f可以指向子类对象,但只能调用自己的方法(丢失了子类的方法和属性),只有子类重写了父类的方法,才能调用子类的方法,才能达到拓展的目的
Father f = new Son();
Son s = new Son();
//子类引用不可以直接指向父类,除非强制转换(Son ss = (Son) new Father();)
// Son ss = new Father();
//父类引用不能直接调用子类的方法,除非强制转换( ((Son) f).own();)或者该方法是重写的
// f.own();
f.test(); //子类的非静态test方法,test()方法被重写了,父类引用可以调用子类的方法了
s.test(); //子类的非静态test方法
}
}
class Father {
public void test(){
System.out.println("父类的非静态test方法");
}
}
class Son extends Father {
//当子类重写了父类的方法时,父类引用只要指向不同的子类对象,就可以调用子类的该方法,实现了不同子类拓展父类功能的目的,这称为重写。快捷键alt + insert
@Override
public void test() {
System.out.println("子类的非静态test方法");
}
public void own(){
}
}
注意:不能重写父类的静态方法
当子类定义相同的静态方法时,实际上只是将父类中的该同名方法进行了隐藏,父类和子类中含有的其实是两个没有关系的方法,父类也无法调用子类的该方法(也可以理解为,静态方法是不需要继承的,可以直接用类名调用,因此不满足重写的条件)
多态
即同一方法可以根据发送对象的不同而采用多种不同的行为方式,也就是重写方法的目的,注意父类的属性和静态方法是没有多态的
一个对象的实际类型是确定的,但可以指向对象的引用类型有很多,多态体现为父类引用可以指向自己的多个子类对象,实现了对不同对象实现不同功能的要求
多态存在的条件
-
有继承关系
-
子类需要重写父类方法
-
父类引用指向子类对象(向上转型)
instanceof关键字
- instanceof关键字判断对象是否属于某个类
类型转换
- 父类引用想要调用子类的方法,需要强制转换为子类
- 子类也可以转换为父类,但是会丢失自己的方法
public class Hello {
public static void main(String[] args) {
//向上转型,丢失了子类的方法和属性
Father s1 = new Son();
Son s2 = new Son();
//子类重写了父类的方法,因此父类可以调用子类的方法
s1.print();
s2.print();
Father s3 = s2;
// s3.own(); //子类转换为父类后,丢失了子类本身的方法,不能再调用own()
//对不同子类,调用同一个方法的实现的功能不同,实现了多态
Father s4 = new Son2();
s4.print();
System.out.println(s1 instanceof Father); //true,instanceof关键字判断对象是否属于某个类或其子类
System.out.println(s1 instanceof Son); //true
System.out.println(s2 instanceof Father); //true
System.out.println(s2 instanceof Son); //true
}
}
class Father {
public void print(){
System.out.println("Father的方法");
}
}
class Son extends Father {
@Override
public void print() {
System.out.println("Son的方法");
}
public void own(){
System.out.println("子类自己的方法");
}
}
class Son2 extends Father {
@Override
public void print() {
System.out.println("Son2的方法");
}
}