基本介绍
面向对象编程有三大特征:封装、继承和多态。
封装(Encapsulation)
封装介绍
封装是指属性私有化,就是把抽象出的数据【属性】和对数据的操作【方法】封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作【方法】,才能对数据进行操作。
封装的理解和好处
- 隐藏实现细节:方法(连接数据库)《--调用(传参),简化编程。
- 增强数据安全性,不能让其他用户随意访问和修改数据。
封装的实现步骤
- 将属性进行私有化private 。【不能直接修改属性】
- 提供一个公共的(public)set方法,用于对属性判断并赋值。
- 提供一个公共的(public)get方法,用于获取属性的值。
pulic void setXxx(类型 参数名){//Xxx表示某个属性
//加入数据验证的业务逻辑
属性=参数名;
}
pulic 返回数据类型 getXxx(类型 参数名){//权限判断,Xxx表示某个属性
return xx;
}
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
this关键字
java虚拟机会给每个对象分配this,代表当前对象。
- this关键字可以用来访问本类的属性、方法、构造器。
- this用于区分当前类的属性和局部变量。
- 访问当前对象的属性语法:this.属性。
- 访问当前对象成员方法的语法:this.方法(参数列表)。
- 访问当前对象构造器语法:this(参数列表);注意只能在构造器中使用(即只能在构造器中访问另一个构造器,必须放在第一条语句)。
- this不能在类定义的外部使用,只能在类定义的方法中使用。
- 封装对象的属性的时候,经尝会使用this关键字。
- 当getter和setter函数参数名和成员函数名重合的时候,可以使用this区别。如:
public void setName(String name) {
this.name = name;
}
继承(Extend)
继承介绍
继承的目的是解决代码复用,让我们的编程更加接近人类思维。当多个类存在相同属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。
继承的基本语法
class 子类 extends 父类{
}
- 子类继承后就会自动拥有父类定义的属性和方法
- 父类又叫超类,基类。
- 子类又叫派生类。
继承的好处
- 代码的复用性提高(子类拥有父类定义的属性和方法,除private修饰的除外)。
- 代码的扩展性和维护性提高。
继承的细节
- 子类继承了所有的属性和方法,非私有的属性和方法可以在子类中直接访问,但是私有属性和方法不能在子类中直接访问,要通过父类提供公共的方法去访问。
- 子类必须调用父类的构造器,完成父类的初始化。
- 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造,如果父类没有提供无参构造,则必须在子类的构造器中用super()去指定使用父类的哪个构造器完成对父类的初始化工作,否则编译不通过。
- 如果希望指定去调用父类的某个构造器,则显示的调用一下:super(参数列表)。
- super在使用时,必须放在构造器第一行(这点与this一样,但super与this不共存)。
- java所有类都是object类的子类,object是所有类的基类。
- 父类构造器的调用不限于直接父类,可以一直往上追溯到知道object类(顶级父类)。
- 子类最多只能继承一个(指直接继承),即Java是单继承机制,如果想让A类继承B类和C类,【B继承C、A继承B】。
- 不能滥用继承,子类和父类之间必须满足is-a的逻辑关系。
class Person{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {//构造方法重载
this.name = name;
this.age = age;
}
public String say(){
return "name='" + name + '\'' +
", age=" + age;
}
}
class Student extends Person{
private String id;
private double score;
public Student(){
//默认调用super(),即Person类的无参构造。
}
public Student(String name, int age, String id, double score) {
super(name, age);//指定调用父类有参构造
this.id = id;
this.score = score;
}
public String say(){//方法重写
return super.say()+'\t'+"id="+id+'\''+
",score="+score;
}
}
super关键字
super代表父类的引用,用于访问父类的属性、方法、构造器。
- 访问父类的属性,但不能访问父类的private属性:super.属性名;
- 访问父类的方法,但不能访问父类的private方法:super.方法名(参数列表);
- 访问父类的构造器:super(参数列表);只能放在构造器第一句,且只能有一句。
super细节
- 当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this、直接访问效果一样。
- super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以直接使用super去访问爷爷类的成员;如果多个基类(上级类)中都有相同的成员,使用super访问遵循就近原则。A—》B—》C,当然也需要遵循访问权限的相关规则。
super和this比较
多态(Polymiorph)
多态介绍
多态即多种状态,方法或对象具有多种形式。同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。简单的说:就是用基类的引用指向子类的对象。是面向对象的第三大特征,多态建立在封装和继承既相互之上。
多态的具体体现
1.方法的多态
重载(Overloading)
重载是允许在同一个类里面,多个同名方法存在,但要求形参列表不同。返回类型可以相同也可以不同。每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。最常用的地方就是构造器的重载。
- 方法名:必须相同。
- 形参列表:必须不同(形参类型或个数或顺序,至少有一样不同,参数名无要求)。
- 返回类型:无要求。
其实简单而言:重载就是对于不同的情况写不同的方法。 比如,同一个类中,写不同的构造函数用于初始化不同的参数。
package com.study.srv.demo3;
public class Demo05 {
public static void main(String[] args) {
Demo05 demo05 = new Demo05();
demo05.test();
demo05.test("jack",23);
demo05.test(23,"jack");
System.out.println(demo05.test("jack"));
}
public void test(){//无参
System.out.println("无参无返回值!");
}
public void test(String name,int age){//有参
System.out.println("有参无返回值:"+name+age);
}
public void test(int age,String name){//参数顺序不同
System.out.println("有参但参数顺序不同无返回值:"+age+name);
}
public String test(String name){//有返回值,但是一定要参数不同,才能算重载
return "有参有返回值:"+name;
}
}
重写(Override)
简单来说:方法覆盖(重写)就是子类中有一个方法和父类中的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的方法。
- 方法名必须相同,返回值类型必须相同。
- 参数列表必须相同。
- 子类方法不能缩小父类方法的访问权限。例如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。
- 构造方法不能被重写。
package com.study.srv.demo3;
public class Demo01 {
public static void main(String[] args) {
Person person = new Person("李宁",24);
System.out.println(person.say());
Student student = new Student("向前",21,"2011301101",87.2);
System.out.println(student.say());
}
}
class Person{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {//构造方法重载
this.name = name;
this.age = age;
}
public String say(){
return "name='" + name + '\'' +
", age=" + age;
}
}
class Student extends Person{
private String id;
private double score;
public Student(){
//默认调用super(),即Person类的无参构造。
}
public Student(String name, int age, String id, double score) {
super(name, age);//指定调用父类有参构造
this.id = id;
this.score = score;
}
public String say(){//方法重写
return super.say()+'\t'+"id="+id+'\''+
",score="+score;
}
}
名称 | 发生范围 | 方法名 | 形参列表 | 返回类型 | 修饰符 |
重载(overload) | 本类 | 必须一样 | 形参类型或个数或顺序,至少有一样不同 | 无要求 | 无要求 |
重写(Override) | 父子类 | 必须一样 | 相同 | 子类重写的方法,返回的类型和父类返回的类型一致,或者是其子类 | 子类方法不能缩小父类方法的访问权限 |
2.对象的多态
父类的引用可以指向本类的对象;
父类的引用可以指向子类的对象;
- 一个对象的编译类型和运行类型可以不一致。
- 编译类型在定义对象时就确定了,不能改变。
- 运行类型可以变化。
- 编译类型看定义时=号的左边,运行类型看=号的右边。
多态细节
多态的前提是:两个对象(类)存在继承关系。
多态向上转型:
- 本质:父类的引用指向了子类的对象。
- 语法:父类类型 引用名=new 子类类型();
- 特点:编译类型看左边,运行类型看右边。 可以调用父类中的所有成员(需遵守访问权限),不能调用子类中特有成员;最终运行效果看子类具体实现。
多态向下转型:
- 语法:子类类型 引用名= (子类类型) 父类引用;
- 只能强转父类的引用,不能强转父类的对象。
- 要求父类的引用必须指向的是当前目标类型的对象。
- 当向下转型后,可以调用子类类型中所有的成员。