封装
- 封装的特点:只能通过规定的方法访问数据。
- 隐藏类的实例细节,方便修改和实现。
- 封装的具体实践步骤
- 修改属性的可见性来限制对属性的访问,一般设为 private。
- 为每个属性创建一对赋值(setter)方法和取值(getter)方法,一般设为 public,用于属性的读写
- 在赋值和取值方法中,加入属性控制语句(对属性值的合法性进行判断)。
public class Employee {
private String name; // 姓名
private int age; // 年龄
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
// 对年龄进行限制
if (age < 18 || age > 40) {
System.out.println("年龄必须在18到40之间!");
this.age = 20; // 默认年龄
} else {
this.age = age;
}
}
public class EmployeeTest {
public static void main(String[] args) {
Employee people = new Employee();
people.setName("丽丽");
people.setAge(35);
System.out.println("姓名:" + people.getName());
System.out.println("年龄:" + people.getAge());
}
}
输出结果
姓名:丽丽
年龄:35
继承
- 定义:在已经存在类的基础上进行扩展,从而产生新的类。已经存在的类称为父类、基类或超类,而新产生的类称为子类或派生类。在子类中,不仅包含父类的属性和方法,还可以增加新的属性和方法。
- 格式:修饰符 子类 extends 父类{类的主体}
- 只允许一个类直接继承另一个类,即子类只能有一个直接父类,但可以有多个间接父类,extends 关键字后面只能有一个类名。
- object是所有类的顶级父类(根类),所有类都直接或简介继承了object类
如下演示方法的继承与重写
public class father {
double A(int x,int y){
return x+y;
}
double B(int m,int n){
return m*n;
}
}
class son extends father {
double A(int x,int y){
return x+2*y;
}
}
主函数
public class test {
public static void main(String[] args) {
son s=new son();
System.out.println(s.A(1,2));
}
}
输出结果5.0
继承下的方法覆写与属性覆盖
子类与父类的成员方法之间存在覆写关系,子类与父类的成员变量之间存在覆盖关系。
如果父类中的成员变量在子类可见,并且成员变量名相同,则称为属性覆盖。
- 父类中int i=4
- 子类中int i=5
调用时以i=5为准。
继承的限制
- 子类不能直接访问父类中的私有成员。
- 子类可以从父类那里继承所有非private的成员变量和方法作为自己的成员,但子类不能直接访问父类的私有成员(包括成员变量和成员方法),如果需要访问私有成员变量,则通过getter和setter方法实现。
- private 修饰的成员只能在本类体中可见
class A{
private int x;
private void showX() { //私有方法
System.out.println(this.x);
}
public void setX(int x) {
this.x=x;
}
public int getX() {
return this.x;
}
}
class B extends A{ } //子类B继承父类A
public class Demo2 {
public static void main(String[] args) {
B b=new B();
b.setX(100);
b.showX(); //错误提示
}
}
- 在子类对象构造之前一定会默认调用父类的构造(默认使用无参构造),以保证父类的对象先实例化,而后再实例化子类对象。
方法覆写与方法重载的区别
- 方法覆写存在于子类与父类之间,方法重载存在于类内部成员方法之间。
- 方法覆写指子类的方法与父类的方法在方法名、参数个数和参数类型等3个方面是完全一致的;而方法重载指方法同名,但参数个数或者参数类型不同。
- 方法覆写时子类中方法的访问权限不能小于父类的方法权限。
class A {
public void show(int x) {}
void display(double y) {}
}
class B extends A { // 子类B继承父类A
public void show(int x) {} //覆写父类的show方法
//重载父类中的display方法
public void display(String msg) {}
}
public class Demo2 {
public static void main(String[] args) {
B b=new B();
b.show(10);//调用子类的show方法
}
}
super关键字
- 访问直接父类中被子类隐藏的同名成员变量。
super.成员变量名;
- 访问直接父类中被子类覆写的同名成员方法。
super.成员方法名(参数表);
- 调用直接父类的构造方法。构造方法不能被继承,_在子类构造方法中,第一条语句默认调用父类的构造方法,不写super()代表默认调用父类的无参构造方法。_因此,子类如果想使用父类的构造方法,必须在子类的构造方法中使用,关键字super来表示,而且super必须是子类构造方法中的第一条有效语句。
super(参数); //该语句必须是构造方法的第一条有效语句。
class Father{
private int x=10;
public Father(int x) {
//默认调用Father父类Object的空构造方法
this.x=x;
}
public void show() {
System.out.println(this.x);
}
}
class Son extends Father{
private int y=20;
public Son(int x,int y) {
super(x); //调用Father的构造方法
this.y=y;
}
public void show() { //子类覆写父类的同名方法
System.out.println(this.y);
}
public void print() {
this.show();//调用Son的show方法
super.show();//调用father的show方法
}
}
多态
- 定义: 是指同一行为,具有多个不同表现形式。
- 实现多态的三个条件:
- 1.继承: 继承或者实现【二选一】
- 2.重写:方法的重写【意义体现:不重写,无意义】
- 3.向上转型:父类引用指向子类对象【fu p=new zi() 】
- 多态体现的格式:
- 父类类型 变量名 = new 子类对象;
- 父类类型:指子类对象继承的父类类型,或者实现的父接口类型
- 多态的好处:
- 多态可以让我们不用关心某个对象到底具体是什么类型,就可以使用该对象的某些方法
对于老板来说,不关心你是讲师还是助教,唯一要做的就是督促你去工作。
- 多态中访问方法和属性
- 多态中访问成员变量:编译看左边,运行也是看左边(父类)
- 如果父类与子类的具有同一个成员变量,但是赋得值不同,以父类中得为准
- 多态中访问成员变量:编译看左边,运行也是看左边(父类)
若调用一个只有父类有,而子类没有的成员变量则报错。
- 多态中访问成员方法:编译看左边,但是运行看右边
父子都有,优先用子,子类没有,父类有,向上找到父类
- 子类有而父类没有则依然报错,可采用转型
若子类有重写,则以重写得为准。
- 为什么成员变量和方法的访问不一样呢,因为成员方法有重写而成员变量没有。
package cn.tedu.oop2;
/*本类用作多态的入门案例*/
public class TestDemo {
public static void main(String[] args) {
//6.创建“纯纯的”对象用于测试
Animal a = new Animal();
Cat c = new Cat();
Dog d = new Dog();
a.eat();//小动物Animal吃啥都行~调用的是父类自己的功能
c.eat();//小猫爱吃小鱼干~调用的是子类重写后的功能
d.eat();//小狗爱吃肉骨头~调用的是子类重写后的功能
/*2.父类对象不可以使用子类的特有功能*/
//a.jump();//报错,Animal类里并没有这个方法
//a.run();//报错,Animal类里并没有这个方法
c.jump();//小猫Cat跳的老高啦~,子类可以调用自己的功能
d.run();//小狗Dog跑的老快啦~,子类可以调用自己的功能
//7.创建多态对象进行测试
/*3.口诀1:父类引用指向子类对象
* 解释:创建出来的子类对象的地址值,交给父类类型的引用类型变量来保存*/
Animal a2 = new Cat();//Cat类对象的地址值交给父类型变量a2来保存
Animal a3 = new Dog();//Dog类对象的地址值交给父类型变量a3来保存
//8.测试多态对象
/*4.口诀2:编译看左边,运行看右边
* 解释:必须要在父类定义这个方法,才能通过编译,把多态对象看作是父类类型
* 必须要在子类重写这个方法,才能满足多态,实际干活的是子类*/
a2.eat();//小猫爱吃小鱼干~,多态对象使用的是父类的定义,子类的方法体
}
}
/*1.多态的前提:继承+重写*/
//1.创建父类
class Animal{
//3.创建父类的普通方法
public void eat(){
System.out.println("小动物Animal吃啥都行~");
}
}
//2.1创建子类1
class Cat extends Animal{
//4.1添加重写的方法
public void eat(){
System.out.println("小猫爱吃小鱼干~");
}
//5.1添加子类的特有功能
public void jump(){
System.out.println("小猫Cat跳的老高啦~");
}
}
//2.2创建子类2
class Dog extends Animal{
//4.2添加重写的方法
@Override
public void eat(){
System.out.println("小狗爱吃肉骨头~");
}
//5.2添加子类的特有功能
public void run(){
System.out.println("小狗Dog跑的老快啦~");
}
}
多态的转型
向上转型
父类引用指向子类对象
类A是类B的父类,把子类对象b的引用赋值给父类的对象a,称对象b是对象a的上转型对象。
- 格式:父类类名 对象名=new 子类类名。
- 向上转型就是把子类对象直接赋给父类引用,不用强制转换。
- 使用向上转型可以调用父类类型中的所有成员,不能调用子类类型中特有成员,如果子类重写了父类的某个实例方法后,当用上转型对象调用这个实例方法时一定是调用了子类重写的实例方法。
- 子类进行了向上转型,就失去了调用父类中没有的方法的权力,只能调用父类中存在的方法,
class Person{
public int x=10;
public void show() {
System.out.println("Person的show");
}
}
class Student extends Person{
public int y=20; //新定义成员变量
public void print() { //新增成员方法
System.out.println("Student的print");
}
public void show() { //重写父类方法
System.out.println("Student的show");
}
}
public class Demo {
public static void main(String []args) {
Person per= new Student(); //自动把学生对象转换成Person对象
System.out.println(per.y); //不能访问新增的成员变量
System.out.println(per.x);
per.print(); //不能访问新增的成员方法
per.show(); //访问被子类重写的show方法
}
}
向下转型
子类对象指向父类引用
- 向下转型必须进行强制类型转换
格式 :A a = new B( );B b= (B) a; //强制向下转型
类A是类B的父类,把父类对象a的引用赋值给子类的对象b,称对象a是对象b的下转型对象。
Parent p = new Child();//向上转型,此时,p是Parent类型