JavaSE学习笔记(3)---面向对象三大特性

JavaSE学习笔记(3)---面向对象三大特性

面向对象的三大特征:继承、封装、多态java

1.封装

面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界没法直接操做和修改。而后封装能够被认为是一个保护屏障,防止该类的代码和数据被其余类随意访问。要访问该类的数据,必须经过指定的方式。适当的封装可让代码更容易理解与维护,也增强了代码的安全性。其原则就是将属性隐藏起来,若须要访问某个属性,提供公共方法对其访问。程序员

1.封装的步骤

  • 使用 private 关键字来修饰成员变量。
  • 对须要访问的成员变量,提供对应的一对 getXxx 方法 、 setXxx 方法。

2.封装的操做——private关键字

  1. private的含义编程

    • private是一个权限修饰符,表明最小权限。安全

    • private能够修饰成员变量和成员方法。编程语言

    • 被private修饰后的成员变量和成员方法,只在本类中才能访问。ide

  2. private的使用格式
    private 数据类型 变量名;
    使用 private 修饰成员变量,代码以下:函数

    public class Student {
             private String name;
             private int age;
         }
  3. 提供 getXxx 方法 / setXxx 方法,能够访问成员变量,代码以下:学习

public class Student {
            private String name;
            private int age;
            public void setName(String n) {
               name = n;  
            }
            public String getName() {
               return name;  
            }
            public void setAge(int a) {
               age = a;  
            }
            public int getAge() {
               return age;  
            }
        }

3.封装优化1——this关键字

  • this的含义
    this表明所在类的当前对象的引用(地址值),即对象本身的引用。记住 :方法被哪一个对象调用,方法中的this就表明那个对象。即谁在调用,this就表明谁。测试

  • this使用格式优化

    this.成员变量名;

    使用 this 修饰方法中的变量,解决成员变量被隐藏的问题,代码以下:

public class Student {
        private String name;
        private int age;
        public void setName(String name) {
            //name = name;
            this.name = name;
        }
        public String getName() {
            return name;
        }
        public void setAge(int age) {
            //age = age;
            this.age = age;
        }
        public int getAge() {
            return age;
        }
    }

小贴士:方法中只有一个变量名时,默认也是使用 this 修饰,能够省略不写。

4.封装优化2——构造方法

​ 当一个对象被建立时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。

​ 不管你与否自定义构造方法,全部的类都有构造方法,由于Java自动提供了一个无参数构造方法,一旦本身定义了构造方法,Java自动提供的默认无参数构造方法就会失效。

构造方法的定义格式:
修饰符 构造方法名(参数列表){ // 方法体 }
构造方法的写法上,方法名与它所在的类名相同。它没有返回值,因此不须要返回值类型,甚至不须要void。使用构造方法后,代码以下:

public class Student {
            private String name;
            private int age;
            // 无参数构造方法
            public Student() {}
            // 有参数构造方法
            public Student(String name,int age) {
             this.name = name;    
             this.age = age;     
            }
        }

注意事项
若是你不提供构造方法,系统会给出无参数构造方法。
若是你提供了构造方法,系统将再也不提供无参数构造方法。
构造方法是能够重载的,既能够定义参数,也能够不定义参数。

  1. 标准代码——JavaBean
    JavaBean 是 Java语言编写类的一种标准规范。符合 JavaBean 的类,要求类必须是具体的和公共的,而且具备无参数的构造方法,提供用来操做成员变量的 set 和 get 方法。

    public class ClassName{
        //成员变量
        //构造方法
        //无参构造方法【必须】
        //有参构造方法【建议】
        //成员方法 
        //getXxx()
        //setXxx()
    }

编写符合 JavaBean 规范的类,以学生类为例,标准代码以下:

public class Student {
    //成员变量
    private String name;
    private int age;
    //构造方法
    public Student() {}
    public Student(String name,int age) {
        this.name = name;
            this.age = age;
        }
        //成员方法
        publicvoid setName(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
        publicvoid setAge(int age) {
            this.age = age;
        }
        publicint getAge() {
            return age;
        }
    }

测试类,代码以下:

    public class TestStudent {
        public static void main(String[] args) {
            //无参构造使用
            Student s= new Student();
            s.setName("小米");
        s.setAge(18);
        System.out.println(s.getName()+"‐‐‐"+s.getAge());
        //带参构造使用
        Student s2= new Student("小明",18);
        System.out.println(s2.getName()+"‐‐‐"+s2.getAge());
    }
}

封装是很是有必要的,由于:

  1. 封装提升了数据的安全性
    别人不可以经过变量名.属性名的方式来修改某个私有的成员属性
  2. 操做简单封装后,多个调用者在使用的时候,只需调用方法便可,调用者不须要再进行判断
  3. 隐藏了实现
    实现过程对调用者是不可见的,调用者只需调用方法便可,不知道具体实现过程

继承

​ 现实生活中的继承,孩子继承父辈的财产,孩子能够直接拿父辈的财产来使用,Java中的继承是指在现有类的基础上定义一个新的类,现有类称为父类,新的类称为子类,子类会自动拥有父类的可继承的内容多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那一个类便可。内容

1. 继承的定义

继承:

就是子类继承父类的属性和行为,使得子类对象具备与父类相同的属性、相同的行为。子类能够直接访问父类中的非私有的属性和行为。
好处

  • 提升代码的复用性。
  • 类与类之间产生了关系,是多态的前提。

2.继承的格式

经过extends关键字,能够声明一个子类继承另一个父类,定义格式以下:

class 父类 {
...    
}
class 子类 extends 父类 {
...    
}

举个例子,代码以下:

// 1.定义父类
class Person {
    String name;
    int age;
    public void eat() {
        System.out.println(name + " 吃饭");
    }
    public void sleep() {
        System.out.println(name + " 睡觉");
    }
}
// 2.再写子类
class Student extends Person {
}
class Teacher extends Person {
}

// 3.定义测试类
public class Demo01 {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.name = "小王";
        stu.age = 18;
        stu.eat();
        stu.sleep();
        Teacher tea = new Teacher();
        tea.name = "马老师";
        tea.age = 30;
        tea.eat();
        tea.sleep();
        Person p = new Person();
        p.name = "张三";
        p.age = 20;
        p.eat();
        p.sleep();
    }
}

3.继承案例

请使用继承定义如下类:
1.程序员(Coder)
成员变量: 姓名,年龄
成员方法: 吃饭,睡觉,敲代码
2.老师(Teacher)
成员变量: 姓名,年龄
成员方法: 吃饭,睡觉,上课

1. 父类Person类
    public class Person {
        String name;
        int age;
        public void eat() {
            System.out.println(name + "吃饭");
        }
        public void sleep() {
            System.out.println(name + "睡觉");
        }
    }
2. 子类Coder类
    public class Coder extends Person {
        // 敲代码
        public void coding() {
            System.out.println(name + "敲代码");
        }
    }
3. 子类Teacher类
    public class Teacher extends Person {
        public void teach() {
            System.out.println(name + "上课");
        }
    }
4. 测试类
    public class Demo02 {
        public static void main(String[] args) {
            Coder c = new Coder();
            c.name = "马化腾";
            c.age = 45;
            c.eat();
            c.sleep();
            c.coding();
            System.out.println("‐‐‐‐‐‐‐‐‐‐‐");
            Teacher t = new Teacher();
            t.name = "马云";
            t.age = 50;
            t.eat();
            t.sleep();
            t.teach();
        }
    }

4.父类不可被继承的内容

并非父类的全部内容均可以给子类继承的,如下2个内容不能被子类继承:

  1. 被private修饰的
  2. 构造方法不能继承
  3. 被finall关键字修饰的类不能被继承
    经过getter/setter方法访问父类的private成员变量
public class Demo03 {
    public static void main(String[] args) {
        Zi z = new Zi();
        System.out.println(z.num1);
           // System.out.println(z.num2); // 私有的子类没法使用      
        // 经过getter/setter方法访问父类的private成员变量
        System.out.println(z.getNum2());
        z.show1();
        // z.show2(); // 私有的子类没法使用
    }
}
class Fu {
    public Fu() {
    }
    public int num1 = 10;
    private int num2 = 20;
    public void show1() {
        System.out.println("show1");
    }
    private void show2() {
        System.out.println("show2");
    }
    public int getNum2() {
        return num2;
    }
    public void setNum2(int num2) {
        this.num2 = num2;
    }
}
class Zi extends Fu {
/* 2. 构造方法不能继承,由于构造方法和类名相同,父类和子类的名称确定不相同,没法继承 */ 
// public Fu() {  
// }  
}
  1. 修饰类: 修饰的类不能被继承。好比:Math、String等。
final  class A {}

图5-22 final修饰类.png

5. 继承后的特色——成员变量

成员变量不重名
若是子类父类中出现不重名的成员变量,这时的访问是没有影响的。

成员变量重名
若是子类父类中出现重名的成员变量,这时的访问是有影响的。子父类中出现了同名的成员变量时,在子类中须要访问父类中非私有成员变量时,须要使用 super 关键字,修饰父类成员变量,相似于以前学过的 this 。
使用格式:super.父类成员变量名

注意: 父类中的成员变量是非私有的,子类中能够直接访问。若父类中的成员变量私有了,子类是不能直接访问的。一般编码时,咱们遵循封装的原则,使用private修饰成员变量,那么如何访问父类的私有成员变量呢,能够在父类中提供公共的getXxx方法和setXxx方法。

6.继承后的特色——成员方法

成员方法不重名
若是子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。

成员方法重名——重写(Override)
若是子类父类中出现重名的成员方法,这时的访问是一种特殊状况,叫作 方法重写 (Override) 。
方法重写 :子类中出现与父类如出一辙的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,从新实现。

注意事项
1.子类方法覆盖父类方法,必需要保证权限大于等于父类权限。
2.子类方法覆盖父类方法,返回值类型、函数名和参数列表都要如出一辙。

7.继承后的特色——构造方法

当类之间产生了关系,其中各种中的构造方法,又产生了哪些影响?

  • 构造方法的名字是与类名一致的。因此子类是没法继承父类构造方法的。

  • 构造方法的做用是初始化成员变量的。因此子类的初始化过程当中,必须先执行父类的初始化动做。子类的构造方法中默认有一个 super() ,表示调用父类的构造方法,父类成员变量初始化后,才能够给子类使用。

  • 继承后子类构造方法特色:子类全部构造方法都会调用父类的无参构造

多态

生活中,好比跑的动做,小猫、小狗和大象,跑起来是不同的。再好比飞的动做,昆虫、鸟类和飞机,飞起来也是不同的。可见,同一行为,经过不一样的事物,能够体现出来的不一样的形态。多态,描述的就是这样的状态。

1. 多态的定义

多态: 是指同一行为,具备多个不一样表现形式。

多态指的是同一个方法调用,因为对象不一样可能会有不一样的行为。现实生活中,同一个方法,具体实现会彻底不一样。 好比:一样是调用人的“休息”方法,张三是睡觉,李四是旅游,程序员是敲代码,数学教授是作数学题; 一样是调用人“吃饭”的方法,中国人用筷子吃饭,英国人用刀叉吃饭,印度人用手吃饭。

多态的要点:

  1. 多态是方法的多态,不是属性的多态(多态与属性无关)。

  2. 多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类对象。

  3. 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。

class Animal {
    public void shout() {
        System.out.println("叫了一声!");
    }
}
class Dog extends Animal {
    public void shout() {
        System.out.println("汪汪汪!");
    }
    public void seeDoor() {
        System.out.println("看门中....");
    }
}
class Cat extends Animal {
    public void shout() {
        System.out.println("喵喵喵喵!");
    }
}
public class TestPolym {
    public static void main(String[] args) {
        Animal a1 = new Cat(); // 向上能够自动转型
        //传的具体是哪个类就调用哪个类的方法。大大提升了程序的可扩展性。
        animalCry(a1);
        Animal a2 = new Dog();
        animalCry(a2);//a2为编译类型,Dog对象才是运行时类型。
         
        //编写程序时,若是想调用运行时类型的方法,只能进行强制类型转换。
        // 不然通不过编译器的检查。
        Dog dog = (Dog)a2;//向下须要强制类型转换
        dog.seeDoor();
    }
 
    // 有了多态,只须要让增长的这个类继承Animal类就能够了。
    static void animalCry(Animal a) {
        a.shout();
    }
 
    /* 若是没有多态,咱们这里须要写不少重载的方法。
     * 每增长一种动物,就须要重载一种动物的喊叫方法。很是麻烦。
    static void animalCry(Dog d) {
        d.shout();
    }
    static void animalCry(Cat c) {
        c.shout();
    }*/
}

2.对象的转型

父类引用指向子类对象,咱们称这个过程为向上转型,属于自动类型转换。

向上转型后的父类引用变量只能调用它编译类型的方法,不能调用它运行时类型的方法。这时,咱们就须要进行类型的强制转换,咱们称之为向下转型!

示例 对象的转型

public class TestCasting {
    public static void main(String[] args) {
        Object obj = new String("new"); // 向上能够自动转型
        // obj.charAt(0) 没法调用。编译器认为obj是Object类型而不是String类型
        /* 编写程序时,若是想调用运行时类型的方法,只能进行强制类型转换。
         * 否则通不过编译器的检查。 */
        String str = (String) obj; // 向下转型
        System.out.println(str.charAt(0)); // 位于0索引位置的字符
        System.out.println(obj == str); // true.他们俩运行时是同一个对象
    }
}

在向下转型过程当中,必须将引用变量转成真实的子类类型(运行时类型)不然会出现类型转换异常ClassCastException。

类型转换异常

public class TestCasting2 {
    public static void main(String[] args) {
        Object obj = new String("news");
        //真实的子类类型是String,可是此处向下转型为StringBuffer
        StringBuffer str = (StringBuffer) obj;
        System.out.println(str.charAt(0));
    }
}

为了不出现这种异常,咱们可使用学过的instanceof运算符进行判断,以下所示:

向下转型中使用instanceof

public class TestCasting3 {
    public static void main(String[] args) {
        Object obj = new String("news");
        if(obj instanceof String){
            String str = (String)obj;
            System.out.println(str.charAt(0));
        }else if(obj instanceof StringBuffer){
            StringBuffer str = (StringBuffer) obj;
            System.out.println(str.charAt(0));
        }
    }
}
相关文章
相关标签/搜索