面向对象语言的三大特征
面向对象的三大特征是:封装、继承、多态
封装
封装的概念:
就是将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作与访问。
封装的好处:
1、可以隐藏类的实现细节
2、方便加入控制语句
3、方便修改实现
4、只能通过规定方法进行访问
权限修饰符private就拿来可以进行封装
public class Demo {
public static void main(String[] args) {
Person person = new Person();
//存数据
person.setName("张三");
person.setAge(20);
//读出数据
System.out.println(person.getName());
System.out.println(person.getAge());
}
}
public class Person {
//这就是一个简单的封装,将name和age进行了封装,使外界不能直接调取赋值
// 需要通过方法的调用才能存入数据或查询出数据
private String name;
private int age;
public void setName(String name) {
//必须调用这个方法,才能存取name这个变量的值
if (name != null) {
//this表示当前正在操作的对象
this.name = name;
}
}
public void setAge(int age) {
//必须调用这个方法,才能存取age这个变量的值
if (age >= 0) {
this.age = age;
}
}
public String getName() {
//调用这个方法,才能读取到name这个值
return name;
}
public int getAge() {
//调用这个值,才能读取大age这个值
return age;
}
}
关键字:this
this关键字代表自身类的对象。
使用this关键字引用成员变量,
使用this关键字引用成员变量
this关键字必须放在非静态方法里
上面的代码里也有演示出this这个关键字作用
继承
儿子 继承 父亲
继承是面向对象程序设计不可缺少的设计思想,是实现代码可重复使用的根基,是提高代码可拓展性的主要途径。
继承就是从已有的类中派生出新的类,新的类能吸收已有类的属性和行为,并能扩展出新的能力
优点:儿子可以使用父亲的功能, 提高代码的复用性
在Java中使用extends关键字来表示继承关系。
Java不支持多继承,单继承使得Java的继承关系很简单,一个类只能存在一个直接的父类。
继承之后子类可以调用父类的所有非私有属性和非私有的方法。
继承具有传递性,C类继承了B类,B类继承了A类,那么C类就具有了B类和A类的所有非私有的属性和方法。
当一个类没有继承任何类时,JVM就会默认的继承Object类,如果有继承父类,那么它的父类或者父类的父类就会继续Object类。(继承的传递性)
Object类是java内所有类提供的一种基类。(父类、超类)
何时使用继承
符合is-a关系的设计,使用继承。将子类共有的属性和行为放到父类当中
继承也是代码重用的一张方式
package com.functorone;
public class Test {
public static void main(String[] args) {
Dog xh = new Dog();
//虽然Dog类中什么都没有写,但是因为extends继承了Animal类,
// 所以也就有了Animal中的行为属性(非私有的)
xh.setName("小黑");
xh.setAge(6);
xh.eat();
xh.sleep();
//调用子类特有的行为属性
xh.setType("哈士奇");
xh.play();
}
}
package com.functorone;
//父类
public class Animal {
private String name;
private int age;
public void eat() {
System.out.println("动物吃东西");
}
public void sleep() {
System.out.println("动物睡觉");
}
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;
}
}
package com.functorone;
//Dog类,继承Animal类
public class Dog extends Animal {
private String type;
public void play() {
System.out.println("狗会接飞盘");
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
继承中的构造方法
子类构造方法总是先调用父类的构造方法,默认情况下,调用父类无参构造方法,可以在子类构造方法的第一行,使用super关键字调用父类的任意构造方法。
如果要使用super,必须写在所要调用子类构造方法内的第一行。
如果子类的构造方法没有显示的调用基类的构造方法,则系统默认的调用父类无参的构造方法。
当创建一个子类对象时,会在子类的构造方法中调用父类的构造方法,先去初始化父类。
默认会在构造方法中的第一行使用super()调用,如果显示的使用super调用,也必须在第一行。可以使用super()传参,调用指定的构造方法。
package com.functorone;
public class Test {
public static void main(String[] args) {
Dog xh = new Dog();
}
}
package com.functorone;
//Dog类,继承Animal类
public class Dog extends Animal {
private String type;
public Dog() {
//super(); //用来调用父类的构造方法,是默认存在的,如果我们使用super显示的调用,
// 则必须放在构造方法的第一行
super("大猫");
System.out.println("Dog的无参构造");
}
//一般情况下,当出现有参的构造方法时,尽量写上无参的构造方法。
}
package com.functorone;
//父类
public class Animal {
private String name;
private int age;
public Animal() {
System.out.println("Animal的无参构造");
}
public Animal(String s) {
System.out.println("Animal的有参构造");
}
}
super
super() 表示调用父类的构造方法。
super关键字表示父类的引用,在程序中的主要用途
1、在子类的构造方法当中调用父类的构造方法,需要特别主要,super()语句只能出现在子类构造方法当中的第一行。
2、用 super.成员变量名 可以用来引用父类的成员变量。
3、用 super.方法名(参数列表)的方式来访问父类的方法。
super()只有在调用父类的构造方法时,需要写在子类构造方法的第一行。
package com.functorone;
public class Test {
public static void main(String[] args) {
Dog xh = new Dog();
xh.setName("小黑");
xh.play();
xh.eat();
}
}
package com.functorone;
//父类
public class Animal {
private String name;
private int age;
public void sleep() {
System.out.println("动物睡觉");
}
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;
}
}
package com.functorone;
//Dog类,继承Animal类
public class Dog extends Animal {
private String type;
public void play() {
System.out.println(super.getName() + "狗会接飞盘");
//super值向的是xh这个对象的父类中的getName方法
}
public void eat() {
System.out.println(this.getName() + "狗会吃骨头");
//this值的是调用这个类的对象,xh 但是这个类继承了Animal这个类,所以也直接指向了父类的getName
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
方法的重写(overRide)
方法的重写发生在子类继承父类时,子类对父类方法的重写。
因为父类中的方法不能实现子类所需求的,所以进行重写。
重写的意思就是覆写,将父类存在的方法在子类又重新以一种不同的意思进行了一个重新写的意思。
方法重写的规则:
1、方法名相同,列表名也相同。
2、返回值类型相同。
3、访问权限不能小于父类的访问权限。
注意:构造方法和静态方法是不能重写的,成员变量也不存在重写
package com.functorone;
public class Test {
public static void main(String[] args) {
//调用父类的eat()这个方法。
Animal animal = new Animal();
animal.eat();
//调用了子类当中的eat()这个方法
//子类的eat()这个方法会覆盖掉父类中的这个方法
Dog xh = new Dog();
xh.eat();//调用的是Dog类当中重写的eat()方法。
}
}
package com.functorone;
//父类
public class Animal {
public void eat() {
System.out.println("动物吃东西");
}
}
package com.functorone;
//Dog类,继承Animal类
public class Dog extends Animal {
//当父类中的方法已经不能在满足子类的需求时,可以在子类的方法当中将父类进行重写
@Override //java中的注解标签 说明此方法是从父类当中重写过来的 在编译期间就会对语法进行校验
// 一般在重写的方法前面加上这个以表示这个方法是重写的方法。
public void eat() {
super.eat(); //调用父类当中的eat这个方法
System.out.println("狗会吃骨头");
}
}
多态
多态:指同一事物,在不同时刻表现出来的不同状态
多态存在的三个必要的条件。
1、要有继承(包括接口的实现)(前提条件)
2、要有方法重写(前提条件)
3、父类引用指向子类的对象
父类的引用指向子类的对象,就例如 List list = new ArrayList(); 这种写发是正确的,在正常情况下,应该为ArrayList list = new ArrayList(); 因为List是ArrayList的父类,所以也是可以拿List类型来接ArrayList
Object obj = new Car(); 这个也是对的,因为Object类是 java中的基类,是所有类的基类。
这就是父类的引用指向了子类的对象。
特征
● 当编译期间调用的父类当中的方法,运行期间调用的是子类中的方法,就被称为父类引用子类的对象。
● 多态环境下对成员方法的调用
例如:Animal dg = new Dog();
就是编译看左边,运行看右边
● 多态环境下对静态方法的调用
对于静态方法,编译和运行都是看左边的
● 多态环境下对成员变量的调用
编译和运行都是看等号左边的
注意:变量不存在被子类覆写的这一说法,只有方法才有覆写这种说法
● 方法参数具有多态性
方法参数具有多态性的好处:提高代码的扩展性
package com.functorone;
public class Test {
public static void main(String[] args) {
Animal dg = new Dog(); //这就是多态。父类的引用指向子类的对象
dg.sleep(); //这个dg虽然是Animal的引用,但是它调的是子类Dog中的方法
dg.eat(); //对于静态方法,编译和运行都看左边
System.out.println(dg.name); //对于成员变量来说,编译和运行都是看左边的
dg = new Cat();
dg.sleep();
//调用都是调的Animal这个类
}
}
package com.functorone;
public class Demo {
/*
* 方法参数的多态性
* */
/*
public static void main(String[] args) {
Demo demo = new Demo();
Dog dog = new Dog();
demo.sleepdog(dog);
Cat cat = new Cat();
demo.sleepcat(cat);
}
public void sleepdog(Dog dog){
dog.sleep();
}
public void sleepcat(Cat cat){
cat.sleep();
}*/
//在这里就可以使用多态性,可以增加代码的扩展性
// 上下的代码意义完全相同,但是当有大量数据时,明显下面的代码更简洁
public static void main(String[] args) {
Demo demo = new Demo();
Dog dog = new Dog();
Cat cat = new Cat();
demo.sleep(dog);
demo.sleep(cat);
}
//在这提高了扩展性
public void sleep(Animal animal) {
//这里一定是要采用他们的父类或者中祖类的类型
//方法的形式参数类型是父类类型,而传递的实际参数可以是任意子类的对象
animal.sleep();
}
}
package com.functorone;
public abstract class Animal {
String name = "Animal";
public abstract void sleep();
public static void eat() {
System.out.println("Animal吃东西");
}
}
package com.functorone;
public class Dog extends Animal {
String name = "Dog";
@Override
public void sleep() {
System.out.println("Dog睡觉");
}
public static void eat() {
System.out.println("Dog吃骨头");
}
}
package com.functorone;
public class Cat extends Animal {
@Override
public void sleep() {
System.out.println("Cat睡觉");
}
}
多态的转型
向上转型
向上转型的作用就是为了提高程序扩展性
就是把小的类型转换为大的类型
将子类类型转为父类的类型,那么父类的类型也是可以用来表示子类的类型
就是上面所说的父类引用子类的对象
多态的一个缺点,父类的类型是不能访问到子类中所特有的方法,所以就出现了向下转型
向下转型
就时将大的类型转换为小的数据类型。
package com.functorone;
public class Demo {
//在这里就可以使用多态性,增加了代码的扩展性
public static void main(String[] args) {
Demo demo = new Demo();
Dog dog = new Dog();
Cat cat = new Cat();
demo.sleep(dog);
demo.sleep(cat);
}
//在这提高了扩展性
public void sleep(Animal animal) { //这里一定是要采用他们的父类或者中祖类的类型
animal.sleep();
//我们在这想调用Dog类当中所特有的play这个方法
//所以我们就要出现了一个向下转型的问题
if (animal instanceof Dog) { //返回值为:true、false
//instanceof 是用来检测 父类引用中表示的对象的类型 是否为指定的类型
Dog dog = (Dog) animal;
dog.play(); //这样就可以调用到Dog类中专属的play这个方法
}
}
}
package com.functorone;
public abstract class Animal {
public abstract void sleep();
}
package com.functorone;
public class Dog extends Animal {
@Override
public void sleep() {
System.out.println("Dog睡觉");
}
//play这个方法是Dog这个类中特有的方法
public void play() {
System.out.println("Dog会接飞盘");
}
}
package com.functorone;
public class Cat extends Animal {
@Override
public void sleep() {
System.out.println("Cat睡觉");
}
}
instanceof
再多态中向下转型当中,会出现所要转换的不是指定的类型,这里就要用到instanceof判断运算符来判断类型是否一致。且返回类型为布尔型(true/false)
A instanceof B
表示的意思就是A引用中表示的数据类型是否为指定B的数据类型
是返回true,不是就返回false