JavaSE学习之道:面向对象的三大特征

来源:互联网 发布:mac下载安装虚拟机 编辑:程序博客网 时间:2024/05/20 07:51

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

 

2.     封装:隐藏对象的属性和实现细节,仅对外公开接口,控制程序中属性的读和修改的访问权限,将抽象得到的数据和行为相结合,形成“类”,其中数据和方法都是类的成员。封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,以特定的访问方式来使用类的成员。

封装的基本要求是:把所有的属性私有化,对每个属性提供getter和setter方法,如果有一个带参的构造函数的话,那一定要写一个不带参的构造函数(有带参数的构造器时,系统就不会再自动生成不带参数的构造器了)。

 例如:家里的电视,结构复杂,里面乱七八糟的零件一大堆,但是电视使用起来就是那么简单,为什么?那是因为创维把电视来了个封装,把对用户不重要的东西用个电视机壳把它装起来了,然后给你个遥控器,通过这个遥控器,你就可以操作这台电视机了。也就是说你不需要理解电视内部的构造原理和工作原理,你只要会按按钮就可以了。

分析:封装的必要性,封装可以提高类的安全性,避免其他类修改数据,这个的依据是因为对象可以直接调用该类的属性,已达到通过属性修改数据的目的,例如下所示:

编写一个教师类,要求:

(1)具有属性:姓名、年龄

(2)具有行为:自我介绍

(3)教师的最小年龄要求:22岁

代码示例:

public class Teacher{

       public Stringname;//教员姓名

       public int age;//年龄

       /**

        *返回自我介绍的内容

        */

       public Stringintroduction(){

          return"大家好!我是"+name+",我今年"+age+"";

           }

}

编写一个测试类,要求:实例化一个教员对象,并对其初始化,并在控制台输出该教员的自我介绍,如下所示:

代码示例:

public class TeacherTest{

       public static void main(String[]args){

          Teacherteacher=new Teacher();

          teacher.name="张三";

          teacher.age=9;

          System.out.println(teacher.introduction());

}

}

结果:大家好!我是张三,我今年9岁;

分析:因为没对属性进行封装,所以运行结果不满足教员的最小年龄要求,要满足此要求,就需要通过对属性的封装来实现,修改Teacher类如下:

代码示例:

public class Teacher {

     private Stringname;//教员姓名

        private int age;//年龄

      

 public int getAge() {

          returnage;

        }

 

        public void setAge(int age) {

            if (age < 22) {

               System.out.println("错误!最小年龄应为22岁!");

               this.age = 22;//如果不符合年龄要求,则赋予默认值

            }else {

               this.age = age;

           }

        }

 

        public String getName() {

            returnname;//返回教员姓名

        }

        public void setName(String name) {

           this.name = name;//设定教员姓名

        }

 

        public String introduction() {

           return"大家好!我是" +name +",我今年" +age +"";

            }

}

编写一个测试类,和上面不一样的是,下面的测试是对象调用方法,而不是给对象中的属性赋值。

public class TeacherTest{

       public static void main(String[]args){

          Teacherteacher=new Teacher();

          teacher.setName("张三");

          teacher.setAge(9);

          System.out.println(teacher.introduction());

       }

}

结果:错误!最小年龄应为22岁!

大家好!我是张三,我今年22岁;

分析:封装由于隐藏了自己的属性,其他类不能调用private属性,所以使用隐藏属性的唯一途径就是生成get/set方法,供外界调用,这样不仅可以在get/set方法中设置限定代码,而且还有利于程序的维护和模块化;

问题:我给public属性的也加上set/get方法,不也一样可以限定年龄吗?

解答:如果这样的话,那么测试方法中可以用两种方式初始化Teacher对象了,

代码示例:(第一种方法) 

public class TeacherTest{

       public static void main(String[]args){

          Teacherteacher=new Teacher();

          teacher.name="张三";

          teacher.age=-4;

          System.out.println(teacher.introduction());

       }

}

结果:大家好!我是张三,我今年-4岁

代码示例:(第二种方法) 

public class TeacherTest{

       public static void main(String[]args){

          Teacherteacher=new Teacher();

          teacher.setName("张三");

          teacher.setAge(-4);

          System.out.println(teacher.introduction());

       }

}

结果:错误!最小年龄应为22岁!
     大家好!我是张三,我今年22岁

分析:这样的话set/get方法中所有的限定就没有用了,别人可以用第一种方法(直接对属性的访问)来修改类的限制功能,所以,封装(私有的属性,共有接口方法)能带来好处;

   知识扩展:使一个对象不可变需要有3个步骤:    

(1)数据成员必须是私有的,防止被外部的代码直接地操纵。(private

(2)不能提供setter方式,目的就是不允许对被封装的数据的变更。(可以在类中的属性直接初始化)

(3)类本身必须是最终的,声明类为最终的可以防止另一个类创建不可变类的可变子类。(final关键字:不能被继承)

 

3. 访问修饰符(access modifier)。

1) public(公共的):被public所修饰的属性和方法可以被所有类访问。

2) protected(受保护的):被protected所修饰的属性和方法可以在类内部、相同包以及该类的子类所访问。

3) private(私有的):被private所修饰的属性和方法只能在该类内部使用

4) 默认的(不加任何访问修饰符):在类内部以及相同包下面的类所使用。

 

4. 如果一个java源文件中定义了多个类,那么这些类中最多只能有一个类是public,换句话说,定义的多个类可以都不是public的。

 

5. 方法重载(Overload)。表示两个或多个方法名字相同,但方法参数不同。方法参数不同有两层含义:1)参数个数不同。2)参数类型不同。注意:方法的返回值对重载没有任何影响。

 

6.构造方法重载:只需看参数即可。如果想在一个构造方法中调用另外一个构造方法,那么可以使用this()的方式调用,this()括号中的参数表示目标构造方法的参数。this()必须要作为构造方法的第一条语句,换句话说,this()之前不能有任何可执行的代码。

       程序示例:

    package com.zp.base;

   public class ConstructOverload {

        public ConstructOverload(){

           this(4);//必须写在第一行,调用了第二个带参的构造方法;

           System.out.println("test");

        }

        public ConstructOverload(inti){

           System.out.println(++i);

        }

   

        public static void main(String []args){

           ConstructOverloadc1 = new ConstructOverload();

           ConstructOverloadc2 = new ConstructOverload(3);

        }

}

结果:5  test  4

 

 

7.继承(Inheritence):Java是单继承的,意味着一个类只能从另一个类继承(被继承的类叫做父类【基类】, 继承的类叫做子类),Java中的继承使用extends关键字。

 

8. 当生成子类对象时,Java默认首先调用父类的不带参数的构造方法,然后执行该构造方法,生成父类的对象。接下来,再去调用子类的构造方法,生成子类的对象。【要想生成子类的对象,首先需要生成父类的对象(父类得有无参的构造方法),没有父类对象就没有子类对象。比如说:没有父亲,就没有孩子】。

       程序示例:

    package com.zp.base;

 

  public class Parent {

        public Parent(){

           System.out.println("parent...");

        }

}

 

     package com.zp.base;

public class Child extendsParent {

        public Child(){

           System.out.println("Child...");

        }

   

        public static void main(String []args){

           Childc = new Child();

        }

}

结果:parent...     Child...

 

子类有参数的构造方法和上述结果一样,这样就能得出:无论子类是什么构造方法,都可以创建父类对象,然后生成子类对象;但是如果将父类的构造器改成有参构造器,如下所示:

public class Parent {

        public Parent(int a){

           System.out.println("parent...");

        }

}

则会出现错误如下所示:

    Implicit super constructor Parent() is undefined. Must explicitly invokeanother constructor.

    解决方案:通过在子类构造器中使用super()方法,调用父类带参数构造器

    程序示例:

public class Parent {

        public Parent(int a){

           System.out.println("parent...");

        }

}

 

    package com.zp.base;

public class Child extendsParent {

        public Child(){

           super(1); //此处调用父类带参数的构造方法

           System.out.println("Child...");

        }

   

        public static void main(String []args){

           Childc = new Child();

        }

}

    结果:parent...   Child...

 

9. 关键字:super表示对父类构造方法的调用;this表示对当前类的构造器的调用,必须写在构造器的第一条语句上。

 

10. 如果子类使用super()显式调用父类的某个构造方法,那么在执行的时候就会寻找与super()所对应的构造方法而不会再去寻找父类的不带参数的构造方法。与this一样,super也必须要作为构造方法的第一条执行语句,前面不能有其他可执行语句。

 

11. 关于继承的3点:

a)父类有的,子类也有

b)父类没有的,子类可以增加

c)父类有的,子类可以改变

程序示例:

package com.zp.base;

public class Parent {

    String name ="name = father";

    public Parent(int a){

       System.out.println("parent...");

    }

    public void say(){

       System.out.println("I can say....");

    }

}

package com.zp.base;

public class Child extends Parent {

    String name ="name = son";

    int age = 20;

    public Child(){

       super(1);

       System.out.println("Child...");

    }

    public void study(){

       System.out.println("the son is student....");

    }

    public static void main(String [] args){

       Child c = newChild();

       System.out.println(c.name);

       System.out.println(c.age);

       c.study();

       c.say();

    }

}

结果:parent...

Child...

name = son

20

the son is student....

I can say....

 

12. 关于继承的注意事项

a) 构造方法不能被继承

b) 方法和属性可以被继承

c) 子类的构造方法隐式地调用父类的不带参数的构造方法

d) 当父类没有不带参数的构造方法时,子类需要使用super显式地调用父类的构造方法,super指的是对父类的引用 。

e) super关键字必须是构造方法中的第一行语句。

 

13. 方法重写(Override):又叫做覆写,子类与父类的方法返回类型一样、方法名称一样,参数一样,这样我们说子类与父类的方法构成了重写关系。

 

14. 方法重写与方法重载之间的关系:重载发生在同一个类内部的两个或多个方法。重写发生在父类与子类之间。

 

15. 当两个方法形成重写关系时,可以在子类方法中通过super.say()形式调用父类的say ()方法,其中super. say ()不必放在第一行语句,因此此时父类对象已经构造完毕,先调用父类的run()方法还是先调用子类的say ()方法是根据程序的逻辑决定的。

程序示例:

public class Parent {

      String name = "name = father";

      public Parent(int a){

         System.out.println("parent...");

      }

      public void say(){

         System.out.println("Parent can say....");

      }

}

 

package com.sdjz;

 

public class Child extends Parent{

   public Child(String name) {

      super(1);

      System.out.println("child....");

   }

  

   @Override

   public void say() {

      System.out.println("Child cansay....");

   }

  

   public void study(){

      //super用来调用父类方法,可以放在任何位置,这也是和在构造器中的区别;

      super.say();

      System.out.println("the son isstudent....");

      super.say();

   }

  

   public static void main(String[] args) {

      Child child = new Child("zhangpeng");

      child.say();

      child.study();

   }

}

结果:parent...

child....

Child can say....

Parent can say....

the son is student....

Parent can say....

分析:使用super调用父类方法的时候,如果没有重写父类方法,这时候就没有和父类方法重名的方法了,子类就可以直接调用父类的方法了,但是在子类重写父类方法的时候就只能用super调用父类方法了;

代码示例:(父类和上面代码一样)

public class Child extends Parent{

   public Child(String name) {

      super(1);

      System.out.println("child....");

   }

  

   public void study(){

      say();

   }

  

   public static void main(String[] args) {

      Child child = new Child("zhangpeng");

      child.study();

   }

}

结果:parent...

child....

Parent can say....

 

16. 在定义一个类的时候,如果没有显式指定该类的父类,那么该类就会继承于java.lang.Object类(JDK提供的一个类,Object类是Java中所有类的直接或间接父类)。

 

17. 多态(Polymorphism):即多种形态;我们说子类就是父类(玫瑰是花,男人是人),因此多态的意思就是:父类型的引用可以指向子类的对象。

 

程序示例:

package com.zp.base;

 

public class Parent {

   

    public void say(){

       System.out.println("parent cansay....");

    }

}

 

package com.zp.base;

 

public class Child extends Parent {

   

    public void say(){

       System.out.println("child cansay....");

    }

 

    public static void main(String [] args){

       Parent c = new Child();//多态:父类应用指向子类对象

       c.say();

    }

}

 

18. Parent p = new Child();当使用多态方式调用方法时,首先检查父类中是否有say()方法,如果没有则编译错误;如果有,再去调用子类的say()方法,若子类没有则调用父类的say()方法,p是父类引用,所以是Parent类型的,只是指向了Child类型,只能调用父类有的方法。

 

19. 一共有两种类型的强制类型转换:

a) 向上类型转换(upcast):比如说将Cat类型转换为Animal类型,即将子类型转换为父类型。对于向上类型转换,不需要显式指定。

b) 向下类型转换(downcast):比如将Animal类型转换为Cat类型。即将父类型转换为子类型。对于向下类型转换,必须要显式指定(必须要使用强制类型转换)。

示例:Parent p = new Child(); //向上类型转换;

         p= new Parent();

        Child c = (Child)p; //向下类型转化;

 

20. 一个突出多态简便作用的例子:

 

package com.zp.duotai;

 

public class Car {

   

    public void run(){

       System.out.println("Car isruning....");

    }

}

package com.zp.duotai;

 

public class QQ extends Car{

    @Override

    public void run() {

       System.out.println("QQ isruning.....");

    }

}

 

public class BMW extends Car{

    @Override

    public void run() {

       System.out.println("BMW isruning.....");

    }

}

 

public class Test {

   

    public void run(Car car){//car的引用

       car.run();

    }

   

    public static void main(String[] args) {

       Test test = new Test();

       Car car = new QQ();//多态,

       test.run(car);

    }

}

原创粉丝点击