Java_封装,继承和多态笔记

Posted 过往将来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java_封装,继承和多态笔记相关的知识,希望对你有一定的参考价值。

Java_面向对象—封装与隐藏

程序设计的追求:高内聚,低耦合

  1. 高内聚 :类的内部数据操作细节自己完成,不允许外部干涉;
  2. 低耦合 :仅对外暴露少量的方法用于使用。

使用封装与隐藏的原因

  1. 使用者对类内部定义的属性(对象的成员变量)的直接操作会导致数据的错误、混乱或安全性问题。
  2. 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提
    高系统的可扩展性、可维护性。

封装的概念

  1. 通过将数据声明为私有的(private),再提供公共的(public)方法 :getXxx()和setXxx()实现对该属性的操作

封装的目的

  1. 隐藏一个类中不需要对外提供的实现细节
  2. 使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作;
  3. 在后续需要维护时,便于修改,增强代码的可维护性
package com.company;

public class Java_FZ_test {
    public static void main(String[] args) {
        //    封装的测试
        Java_FZ_test J = new Java_FZ_test();
        J.Zoo();
    }
    public static void Zoo() {
            Animal xb = new Animal();
            xb.legs = 4;
            System.out.println(xb.legs);
            xb.eat();
            xb.move();
    }
    public static class Animal {
        public int legs;
        public void eat(){
            System.out.println("Eating");
        }
        public void move(){
            System.out.println("Moving.");
        }
    }
}

运行结构

Java_封装和继承的操作

  1. Java中通过将数据声明为私有的(private),再提供公共的(public)
    方法:getXxx()和setXxx()实现对该属性的操作,用来隐藏一个类中不需要对外提供的实现细节;
  2. 使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,
    限制对属性的不合理操作;
package com.company;
//    封装的测试
public class Java_FZ_test_02 {
    public static void main(String[] args) {
        Animal xb = new Animal();
        xb.setLegs(4); // xb.setLegs(-1000);
        //xb.legs = -1000; // 非法
        System.out.println(xb.getLegs());

    }
    public static class Animal {
        private int legs;// 将属性legs定义为private,只能被Animal类内部访问
        public void setLegs(int i) {
            if (i != 0 && i != 2 && i != 4) {
                System.out.println("Wrong number of legs!");
                return;
            }
            legs = i;
        }

        public int getLegs() {
            return legs;
        }
    }
}

运行结果

Java_四种访问权限修饰符

  1. Java权限修饰符public、protected、default、private置于类的成员定义前,
    用来限定对象对该类成员的访问权限。
  2. 对于class的权限修饰只可以用public和default。
  3. public类可以在任意地方被访问。
  4. default类只可以被同一个包内部的类访问。

Java_构造器(构造方法)

构造器的特征

  1. 构造器具有与类相同的名称
  2. 构造器不声明返回值类型。(与声明为void不同)
  3. 构造器不能被static、final、synchronized、abstract、native修饰,不能有
    return语句返回值

构造器的作用创建对象;给对象进行初始化

构造器的语法格式修饰符 类名 (参数列表) { 初始化语句; }

package com.company;
public class Java_GouZaoQi_test_01 {
    private int legs;
    // 构造器
    public Java_GouZaoQi_test_01() {
        legs = 4;
        System.out.println("构造器中的:"+legs);
    }
    public void setLegs(int i) {
        legs = i;
        System.out.println("我们传入的:"+i);
    }
    public int getLegs() {
        return legs;
    }
    public static void main(String[] args) {
        Java_GouZaoQi_test_01 j = new Java_GouZaoQi_test_01();
        j.setLegs(5);
    }
}

运行结构

构造器的分类

  1. 隐式无参构造器(系统默认提供)
  2. 显式定义一个或多个构造器(无参、有参)

构造器的注意要点

  1. Java语言中,每个类都至少有一个构造器
  2. 默认构造器的修饰符与所属类的修饰符一致
  3. 一旦显式定义了构造器,则系统不再提供默认构造器
  4. 一个类可以创建多个重载的构造器
  5. 父类的构造器不可被子类继承

Java_构造器的重载

  1. 构造器一般用来创建对象的同时初始化对象
  2. 构造器重载使得对象的创建更加灵活,方便创建各种不同的对象
package com.company;

public class Java_GouZaoQi_02 {

    public Java_GouZaoQi_02() {
        String name = "Java";
        int age = 100;
        System.out.println("无参数构造器:name="+name );
        System.out.println("无参数构造器:age="+age );
    }
    public Java_GouZaoQi_02(String n , int a){
        String name;
        int age;
        name=n; age=a;
        System.out.println("有参数构造器:name="+name );
        System.out.println("有参数构造器:age="+age );
    }
    public static void main(String[] args) {
        String n = "dahj";
        int a = 100;
        Java_GouZaoQi_02 j1 = new Java_GouZaoQi_02();
        Java_GouZaoQi_02 j2 = new Java_GouZaoQi_02(n,100);

    }

}

运行结果

Java_属性赋值过程

  1. 默认初始化
  2. 显式初始化
  3. 构造器中初始化
  4. 通过“对象.属性“或“对象.方法”的方式赋值

Java_JavaBean

  1. JavaBean是一种Java语言写成的可重用组件。

所谓javaBean,是指符合如下标准的Java类:

  1. 类是公共的
  2. 有一个无参的公共的构造器
  3. 有属性,且有对应的get、set方法
  4. 用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以
    用Java代码创造的对象进行打包
  5. 可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关
    心任何改变。

JavaBean样例

	package com.company;
	
	public class Java_JavaBean_01 {
	    private String name; // 属性一般定义为private
	    private int age;
	    public Java_JavaBean_01() {
	    }
	    public int getAge() {
	        return age;
	    }
	    public void setAge(int a) {
	        age = a;
	    }
	    public String getName() {
	        return name;
	    }
	    public void setName(String n) {
	        name = n;
	    }
	}

Java_this简介

  1. 在Java中:this在方法内部使用,即这个方法所属对象的引用;
  2. 在Java中:this在构造器内部使用,表示该构造器正在初始化的对象
  3. this 可以调用类的属性、方法和构造器
  4. 当在方法内需要用到调用该方法的对象时,就用this
  5. 我们可以用this来区分属性和局部变量。比如:this.name = name;

Java_this使用情况

  1. 在任意方法或构造器内,如果使用当前类的成员变量或成员方法可以在其前面添加this,增强程序的阅读性,不过,通常我们都习惯省略this。
  2. 当形参与成员变量同名时,如果在方法内或构造器内需要使用成员变量,必须添加this来表明该变量是类的成员变量
  3. 使用this访问属性和方法时,如果在本类中未找到,会从父类中查找
  4. 当前正在操作本方法的对象称为当前对象。

this样例一

class Person{ // 定义Person类
    private String name ;
    private int age ;
    public Person(String name,int age){
        this.name = name ;
        this.age = age ; }
    public void getInfo(){
        System.out.println("姓名:" + name) ;
        this.speak();
    }
    public void speak(){
        System.out.println("年龄:" + this.age);
    }
}

this样例二

package com.company;

class Person_01{ // 定义Person类
    String name;
    Person_01(String name){
        this.name = name;}
    public void getInfo(){
        System.out.println("Person类 --> " + this.name) ;
    }
    public boolean compare(Person_01 p){
        return this.name==p.name;
    }
}
public class Java_Person{
    public static void main(String args[]){
        Person_01 per1 = new Person_01("张三") ;
        Person_01 per2 = new Person_01("李四") ;
        per1.getInfo() ; // 当前调用getInfo()方法的对象是per1
        per2.getInfo() ; // 当前调用getInfo()方法的对象是per2
        boolean b = per1.compare(per2);
    }
}

使用this调用本类的构造器

class Person{ // 定义Person类
	private String name ;
	private int age ;
	public Person(){ // 无参构造器
		System.out.println("新对象实例化") ;
	}
	public Person(String name){
		this(); // 调用本类中的无参构造器
		this.name = name ;
	}
	public Person(String name,int age){
		this(name) ; // 调用有一个参数的构造器
		this.age = age;
	}
	public String getInfo(){
		return "姓名:" + name + ",年龄:" + age ;
	}
}

Java_this注意事项

  1. 可以在类的构造器中使用"this(形参列表)"的方式,调用本类中重载的其
    他的构造器!
  2. 构造器中不能通过"this(形参列表)"的方式调用自身构造器
  3. 如果一个类中声明了n个构造器,则最多有 n - 1个构造器中使用了
    “this(形参列表)”
  4. "this(形参列表)"必须声明在类的构造器的首行!
  5. 在类的一个构造器中,最多只能声明一个"this(形参列表)"

Java_面向对象编程-继承性

Java_继承性(extends)

  1. 继承存在的意义:多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承存储相同内容的类即可。
  2. 多个类被称为子类(派生类),单独的这个类称为父类(基类或超类)。
  3. 类继承语法格式:class ChildrenClass extends FatherClass{ .... }

Java_继承的作用

  1. 继承的出现减少了代码冗余,提高了代码的复用性
  2. 继承的出现,更有利于功能的扩展。
  3. 继承的出现让类与类之间产生了关系,提供了多态的前提。
  4. 子类继承了父类,就继承了父类的方法和属性。
  5. 在子类中,可以使用父类中定义的方法和属性,也可以创建新的数据和
    方法。
  6. 在Java 中,继承的关键字用的是extends,即子类不是父类的子集,
    而是对父类的“扩展”。

注意:不要仅为了获取其他类中某个功能而去继承

Java_继承的规则

  1. 子类不能直接访问父类中私有的(private)的成员变量和方法。

  1. Java只支持单继承和多层继承,不允许多重继承,一个子类只能有一个父类,一个父类可以派生出多个子类
class SubDemo extends Demo{ } //ok
class SubDemo extends Demo1,Demo2...//error

Java_方法的重写(override/overwrite)

方法重写的定义:

  1. 在子类中可以根据需要对从父类中继承来的方法进行改造,也称
    为方法的重置、覆盖
  2. 在程序执行时,子类的方法将覆盖父类的方法。

方法重写的要求:

  1. 子类重写的方法必须和父类被重写的方法具有相同的方法名称、参数列表
  2. 子类重写的方法的返回值类型不能大于父类被重写的方法的返回值类型
  3. 子类重写的方法使用的访问权限不能小于父类被重写的方法的访问权限
  4. 子类不能重写父类中声明为private权限的方法
  5. 子类方法抛出的异常不能大于父类被重写方法的异常

重写方法时注意:子类与父类中同名同参数的方法必须同时声明为非static的(即为重写),或者同时声明为static的(不是重写)。因为static方法是属于类的,子类无法覆盖父类的方法

重写方法的样例一

public class Person {
	public String name;
	public int age;
	
	public String getInfo() {
		return "Name: "+ name + "\\n" +"age: "+ age;
	}
}
public class Student extends Person {
	public String school;
	public String getInfo() { //重写方法
		return "Name: "+ name + "\\nage: "+ age + "\\nschool: "+ school;
	}
public static void main(String args[]){
		Student s1=new Student();
		s1.name="Bob";
		s1.age=20;
		s1.school="school2";
		System.out.println(s1.getInfo()); //Name:Bob age:20 school:school2
		
		Person p1=new Person();
		p1.getInfo();//调用Person类的getInfo()方法
		
		Student s1=new Student();
		s1.getInfo();//调用Student类的getInfo()方法
		// 这是一种“多态性”:同名的方法,用不同的对象来区分调用的是哪一个方法。
	}
}

重写方法的样例二

class Parent {
		public void method1() {}
}
class Child extends Parent {
	private void method1() {} //非法,子类中的method1()的访问权限private比被覆盖方法的访问权限public小
}
public class UseBoth {
	public static void main(String[] args) {
		Parent p1 = new Parent();
		Child c1 = new Child();
		p1.method1();
		c1.method1();
	}
}

Java_super关键字

  1. 在Java类中使用super来调用父类中的指定操作
  2. super可用于访问父类中定义的属性
  3. super可用于调用父类中定义的成员方法
  4. super可用于在子类构造器中调用父类的构造器
  5. 当子父类出现同名成员时,可以用super表明调用的是父类中的成员
  6. super的追溯不仅限于直接父类
  7. superthis的用法相像,this代表本类对象的引用,super代表父类的内存
    空间的标识
package com.company;

// 关键字 super 实例
class  Person {
    protected  String name = "张三";
    protected int age;
    public String getInfo() {
        return "Name: " + name + "\\nage: " + age;
        }
}
class Student extends Person {
    protected String name = "李四";
    private String school = "New Oriental";
    public String getSchool() {
        return school;
    }
    public String getInfo() {
        return super.getInfo() + "\\nschool: " + school;
    }
}

public class StudentTest {
    public static void main(String[] args) {
        Student st = new Student();
        System.out.println(st.getInfo());
    }
}

运行结果:

Java_super调用父类的构造器

  1. 子类中所有的构造器默认都会访问父类中空参数的构造器
  2. 当父类中没有空参数的构造器时,子类的构造器必须通过this(参数列表)或者super(参数列表)语句指定调用本类或者父类中相应的构造器。同时,只能”二选一”,且必须放在构造器的首行
  3. 如果子类构造器中既未显式调用父类或本类的构造器,且父类中又没有无参的构造器,则编译出错

super 调用父类构造器实例

public class Student extends Person {
	private String school;
	public Student(String name, int age, String s) {
		super(name, age);
		school = s;
	}
	public Student(String name, String s) {
		super(name);
		school = s;
	}
	// 编译出错: no super(),系统将调用父类无参数的构造器。
	public Student(String s) { 
		school = s;
	}
}

Java_this和super的区别

this和super访问属性

  1. this访问本类中的属性,如果本类没有此属性则从父类中继续查找,
  2. super直接访问父类中的属性

this和super调用方法

  1. this访问本类中的方法,如果本类没有此方法则从父类中继续查找
  2. super直接访问父类中的属性

this和super调用构造器

  1. this调用本类构造器,必须放在构造器的首行
  2. super调用父类构造器,必须放在子类构造器的首行

Java_面向对象多态性

  1. 多态性,是面向对象中最重要的概念,在Java中的体现:对象的多态性:父类的引用指向子类的对象
  2. 多态性可以直接应用在抽象类和接口上
  3. Java引用变量有两个类型:编译时类型和运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定,简称:编译时,看左边;运行时,看右边。
  4. 若编译时类型和运行时类型不一致,就出现了对象的多态性(Polymorphism)
  5. 多态情况下,“看左边”:看的是父类的引用(父类中不具备子类特有的方法)
  6. 多态情况下,“看右边”:看的是子类的对象(实际运行的是子类重写父类的方法)

Java_对象的多态性

  1. 对象的多态 :在Java中,子类的对象可以替代父类的对象使用
  2. 一个变量只能有一种确定的数据类型
  3. 一个引用类型变量可能指向(引用)多种不同类型的对象
Person p = new Student();
Object o = new Person();//Object类型的变量o,指向Person类型的对象
o = new Student(); //Object类型的变量o,指向Student类型的对

子类可看做是特殊的父类,所以父类类型的引用可以指向子类的对象:向
上转型(upcasting)。

一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法

	Student m = new Student();
	m.school = “pku”; //合法,Student类有school成员变量
	Person e = new Student(); 
	e.school = “pku”; //非法,Person类没有school成员变量

属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错误。

多态的实例

  1. 方法声明的形参类型为父类类型,可以使用子类的对象作为实参调用该方法
public class Test {
	public void method(Person e) {
		e.getInfo();
	}
	public static void main(Stirng args[]) {
		Test t = new Test();
		Student m = new Student();
		t.method(m); // 子类的对象m传送给父类类型的参数e
	}
}

Java_虚拟方法调用(Virtual Method Invocation)

正常的方法调用

	Person e = new Person();
	e.getInfo();
	Student e = new Student();
	e.getInfo();

虚拟方法调用(多态情况下)

  1. 子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。
	Person e = new Student();
	e.getInfo(); //调用Student类的getInfo()方法

编译时类型和运行时类型

	Person e = new Student();
	e.getInfo(); //调用Student类的getInfo()方法
  1. 编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo()方法。

Java_

以上是关于Java_封装,继承和多态笔记的主要内容,如果未能解决你的问题,请参考以下文章

No2_1.接口继承多态_Java学习笔记_接口

韩顺平 java笔记 第9讲 第10讲 第11讲 第12讲 抽象 封装 继承 多态 方法重载 方法重写

(Object-C)学习笔记 --OC的内存管理封装继承和多态

java学习笔记-多态

Python学习笔记-面向对象进阶封装多态继承

Java_面向对象三大特征:封装继承多态