【黑马程序员】第三章:面向对象(上)

来源:互联网 发布:mac用预览编辑pdf文件 编辑:程序博客网 时间:2024/05/21 09:19

------- Windows Phone 7手机开发、.Net培训、期待与您交流! -------

   Java 是一种面向对象的程序设计语言,了解面向对象的编程思想对于学习 Java 开发相对重要,接下来将讲解如何使用面向对象的思想开发。

一、面向对象的概念


   面向对象是一种符合人类思维习惯的编程思想。现实生活中存在各种形态的不同的事物,这些事务之间存在各种各样联系。在程序中使用对象来映射显示中的事物,使用对象的关系来描述事务之间的联系,这种思想就是面向对象。

   提到妙想对象,自然想到的是面向过程,面向过程就是分析解决问题所需要的步骤,然后用函数把这些步骤一一实现,使用的时候一个一个一次调用就可以了。 面向对象则是把解决的问题按照一定规则划分为多个独立的对象,然后通过调用对象的方法来解决问题。当然一个应用程序会包含多个对象,通过多个对象的相互配合来实现应用程序的功能,这样当应用程序的功能发生变动时,只需要修改个别的对象就可以了,从而是代码更容易得到维护。面向对象的特点主要可以包括封装性继承性多态性

1、封装性

   封装是面向对象的核心思想,将对象的属性和行为封装起来,不需要然外界知道具体的实现细节,这就是封装思想。例如,用户使用电脑,只需要使用手指敲键盘就可以了,无需知道电脑内部是如何工作的,及时用户可能碰巧知道电脑的工作原理,但在使用时并不完全依赖电脑的工作原理这些细节。

2、继承性

   继承性主要描述的是类与类之间的关系,通过继承,可以在无需重新编写原有类的情况下,对原有类的功能进行扩展。例如,有一个汽车类,该类中描述了汽车的普通特性和功能,而轿车的类中不仅包含汽车的特性和功能,还应该增加轿车的特有功能,这时可以让轿车类继承汽车类,在轿车类中单独添加轿车特性的方法就可以了。

   继承不仅增强了代码的复用性,提供了开发效率,而且为程序的修改补充提供了便利。

3、多态性

   多态性指的是在程序中允许出现重名现象,它指在一个类中定义的属性和方法被其他类继承后,他们可以具有不同的数据类型或表现出不同的行为,这使得同一个属性和方法在不同类中具有不同的语义。例如,当听到 " Cut " 这个单词时,理发师的行为时剪发,演员的行为是停止表演,不同的对象所表现的行为是不一样的。

二、类与对象


   面向对象的编程思想力图在程序中对事物的描述与该事物在显示中的形态保持一致。为了做到这一点,面向对象的思想中提出两个概念,即类与对象。其中类是对某一事物的抽象描述,二对象用于表示显示中该类事物的个体。接下来通过一个图例来描述类与对象的关系:

  

   类用于描述多个对象的共同特征,它是对象的模板。对象用于描述显示中的个体,它是类的实例。

1、类的定义

   在面向对象的思想中最核心的就是对象,为了在程序汇总创建对象,首先需要定义一个类。类是对象的抽象,它用于描述一组对象的共同特征和行为。类中可以定义成员变量和成员方法,其中成员变量用于描述对象的特征,也被成为属性,成员方法用于描述对象的行为,可简称为方法。

   在 Java 中,定义在类中的变量称为成员变量,定义在方法中的变量被称为局部变量。如果在某个方法中定义的局部变量与成员变量同名,这种情况是允许的,此时方法中通过变量名访问到的是局部变量,二并非成员变量。成员变量与局部变量的区别如下:

   成员变量:

  • 成员变量定义在类中,在整个类中都可以被访问;
  • 成员变量随着对象的创建而存在,存在于对象所在的对内存中;
  • 成员变量有默认初始化值;

   局部变量:

  • 局部变量只定义在局部范围内,例如 函数内、语句内等;
  • 局部变量存在于栈内存中;
  • 作用的范围结束,变量空间会自动释放;
  • 局部变量没有初始化值;

2、对象的创建和使用

   应用程序想要完成具体的功能,仅有类是远远不够的,还需要根据类创建实例对象。在 Java 程序中可以使用 new 关键字来穿件对象,具体格式如下:

      > 类名   对象名称   =   new   类名();

   在创建对象后,可以通过对象的引用来访问对象所有的成员,具体格式如下:

     >  对象引用 . 对象成员;

class Car{    String color = "red";    int num = 4;    void show(){        System.out.println("color="+color+",num="+num);    }}class CarDemo{    public void main(String[] args){        Car car = new Car();//创建对象        car.color = "black";//对属性进行修改        car.show();//使用对象的功能    }}

   对象的内存结构:

 

3、匿名对象

   匿名对象是对象的简化形式。匿名对象有两种使用情况:

  • 当对对象方法仅做一次调用时;
  • 匿名对象可以作为实际参数进行传递;

4、封装

   所谓类的封装是指定义一个类时,将类中的属性私有化,即使用 private 关键字修饰,私有属性只能在它所在的类中被访问。为了能让外界访问私有属性,需要提供一些使用 public 修饰的共有方法,其中包括获取属性值的 getXxx() 方法和设置属性值的 setXxx() 方法。

   封装的好处:

  • 将变化隔离;
  • 便于使用;
  • 提高重用性;
  • 提高安全性;

   封装原则:

  • 将不需要对外界提供的内容隐藏起来;
  • 把属性都隐藏,提供公共方法对其访问;

class Student{//私有化属性private String name;private int age;//提供对外访问的方法public void setName(String stuName){name = stuName;}public String getName(){return name;}public void setAge(int stuAge){if(stuAge<0)System.out.println("年龄不合法");elseage = stuAge;}public int getAge(){return age;}}

   private 关键字:

  • 是一个权限修饰符;
  • 用于修饰成员(成员变量和成员函数);
  • 被私有化的成员只在本类有效;

三、构造方法

   在之前的知识中学到,实例化一个类的对象后,如果要为这个对象中的属性赋值,则必须要通过直接访问对象的属性或调用 setXxx() 方法才可以。如果需要在实例化对象的同时就为这个对象的属性进行赋值,可以通过构造方法来实现。构造方法是类的一个特殊成员,它会在类实例化对象的时候被自动调用。

1、构造方法的定义

   在一个类中定义的方法如果同时满足一下三个条件,该方法成为构造方法,

  • 方法名与类名相同;
  • 在方法名的前面没有方绘制类型的声明;
  • 在方法中不能使用 return 语句放回一个值;

class Person{public person(){System.ou.println("无参的构造方法被调用了~~~");}}

   在一个类中除了定义无参的构造方法,还可以定义有参的构造方法,通过有参的构造方法就可以实现对属性的赋值。

class Person{    int age;    public person(int a){        age = a;    }    public void speak(){        System.ou.println("I am"+age+"years old");    }}public class Example{    public void main(String[] args){        Person p = new Person(18);        p.speak();    }}

2、构造方法的重载

   与普通方法一样,构造方法也可以重载,在一个雷中可以定义多个构造方法,只要每个构造方法的参数类型或参数个数不同即可。在创建对象时,可以通过调用不同的构造方法为不同的属性赋值。

class Person{String name;int age;public person(String n,int a){name = n;age = a;}public Person(String n){name = n;}public void speak(){System.out.println("大家好,我叫"+name+",我今年"+age+"岁!");}}public class Example(){public void main(String[] args){Person p1 = new Person("张三");Person p2 = new Person("李四",18);p1.speak();p2.speck();}}

   【1】在 Java 中的每个类都至少有一个构造方法,如果在一个类中没有定义构造方法,系统会自动为这个类创建一个默认的构造方法,这个默认的构造方法没有参数,在其方法体中没有任何嗲吗,即什么也不做。

   下面程序中 Person 类的两种写法效果是一样的。

   第一种写法:

   class Person{   }

   第二种写法:

   class Person{      public Person{      }   }

   对于第一种写法,类中虽然没有声明构造方法,但仍然可以用 new Person() 语句来创建 Person 类的实例对象。由于系统提供的构造方法往往不能满足需求,因此我们可以自己在类中定义构造方法,一旦为该类定义了构造方法,系统就不再提供默认的构造方法了。

  注意:既然自己定义了有参的构造方法,系统不会再自动生成无参的构造方法,那么为了避免我们在创建对象时出现错误调用无参方法的情况,最好再定义一个午餐的构造方法。

   【2】声明构造方法时,可以使用 private 修饰吗?

   如果构造方法是私有的,也就无法在类的外部创建该类的实力对象,因此为了方便实力话对象,构造方法通常会使用 public 修饰。

3、构造函数与一般函数的比较

  • 书写格式:两个函数书写格式不同;
  • 调用方式:构造函数在对象创建时被调用,用于初始化,只被执行一次;一般函数在对象创建后,只有被调用才会执行。

4、构造函数和构造代码块的比较

  • 构造代码块:给所有对象初始化,也就是说所有对象调用一个代码块,只要对象一创建,就会被调用。
  • 构造函数:给与之对应的对象初始化,具有针对性。

三、this 关键字

   在构造方法中使用的变量为 n 表示年龄,成员变量使用的是 age,这样的程序可读性很差。这时我们需要将一个类中表示年龄的变量进行统一命名,例如都声明为 age,但是这样做又会导致成员变量和局部变量的名臣冲突,在方法中无法访问成员变量 age。为了解决这个问题,Java 中提供了一个关键字 this,用于在方法中访问对象的其他成员。

   接下来讲解 this 关键字在程序中的三中常见用法:

1、通过 this 关键字可以明确地去访问一个类的成员变量,解决与局部变量名称冲突问题;

class Person{int age;public Person(int age){this.age = age;}public int getAge(){return this.age;}}

2、通过 this 关键字调用成员方法;

class Person{int age;public void openMouth(){...}public void speak(){this.openMouth();}}

3、构造方法是在实例化对象时被 Java 虚拟机自动调用的,在程序中不能像调用其他方法一样去调用构造方法,但可以在一个构造方法中使用 " this([参数1,参数2,...]) " 的形式来调用其他构造方法;

class Person{int age;public Person(){System.out.println("无参的构造方法被调用了...");}public Person(String name){this();System.out.println("有参的构造方法被调用了...");}}

   在使用 htis 关键字调用类的构造方法时,应注意一下几点:

  • 只能在构造方法中使用 this 调用其他的构造方法,不能在成员方法中使用;
  • 在构造方法中,使用 this 调用构造方法的语句必须放在第一行,且只能出现一次;
  • 不能在一个类的两个构造方法中使用 this 互相调用;

四、static 关键字

   在 Java 中,定义了一个 static 关键字,它用于修饰类的成员,如成员变量、成员方法以及代码块等,被 static 修饰的成员具备一些特殊性,接下来逐一讲解。

1、静态变量

   在定义一个类时,只是在描述某类事物的特征和行为,并没有产生具体的数据。只有通过 new 关键字创建该类的实例对象后,系统才会为每个对象分配空间,存储各自的数据。有时候,我们希望某些特定的数据在内存中存有一份,而且被一个类的所有势力对象所共享。例如某个学校所有学生共享同一个学校名称,此时完全不必在每个对象所占用的内存空间中都定义一个变量来表示学校名称,而可以在对象以外的空间定义一个表示学校名称的变量让所有学生对象共享,具体内存中的分配情况如下:

  

   在 Java 类中,可以使用 static 关键字来修饰成员变量,该变量被称为静态变量。静态变量被所有实例共享,可以使用 " 类名 . 变量名 " 的形式来访问。

class Student{static String schoolName;}public class Example{public void main(String[] args){Student stu1 = new Student();Student stu2 = new Student();Student.schoolName = "传智播客";System.out.println("我的学校是"+stu1.schoolName);System.out.println("我的学校是"+stu12.schoolName);}}

   注意:static 关键字只能修饰成员变量,不能用于修饰局部变量,否则会编译失败。

   成员变量和静态变量的区别:

  • 所述对象:

              > 成员变量所属于对象,称为实例对象;

              > 静态变量所属于类,称为类变量。

  • 内存位置:

              > 成员变量随着对象的建立而存在于堆内存中;

              > 静态变量随着类的加载而存在于方法区中。
  • 生命周期:

              > 成员变量的生命周期随着对象的消失而消失;

              > 静态变量的生命周期最长,随着类的消失而消失。
  • 调用方式:

              > 成员变量只能被对象调用;

              > 静态变量可以被对象调用,也可以被类名调用。

         所以,成员变量可以称为对象的特有数据,静态变量称为对象的共享数据。

2、静态方法

   有时我们希望在不创建对象的情况下就可以调用某个方法,换句话说就是使用该方法不必和对象绑定在一起。要实现这样的效果,只需要在类中定义的方法前加上 static 关键字即可,我们称这种方法为静态方法。

   同静态变量一样,静态方法可以使用 " 类名 . 方法名 " 的方式访问,也可以通过类的实例对象来访问。

class Student{public static void sayHello(){System.out.println("hello");}}public class Example{public void main(String[] args){Person.sayHello();}}

3、静态代码块

   在 Java 中,使用一对大括号围起来的若干行代码被称为一个代码块,用 static 关键字修饰的代码块称为静态代码块。当类被加载时,静态代码块会执行,由于类只加载一次,因此静态代码块只执行一次。

   在程序中,通常会使用静态代码块来对类的成员变量进行初始化。

class Student{static String country;static{sountry = "china";}}

4、使用注意

  • 静态方法只能访问静态成员;
  • 静态方法中不可以写 this、super 关键字;
  • 主函数是静态的;

   静态代码块、构造代码块、构造函数的执行顺序:静态代码块 >> 构造代码块 >> 构造函数。

5、main 函数

   主函数是一个特殊的函数,作为程序的入口,可以被 JVM 调用。main 不是关键字,但却是一个特殊的单词,可以被 JVM 识别。

6、单例设计模式

   在编写程序时经常遇到一些典型的问题或需要完成某种特定需求,设计模式就是针对这些问题和需求,在大量时间钟总结和理论化之后优选的代码结构、编程风格以及解决问题的思考方式。

   单例设计模式是 Java 中的一种设计模式,它是指在设计一个类时,需要保证在整个程序运行期间针对该类只存在一个实例对象。

class Single{private static Single INSTANCE = new Single();private Single(){}public static Single getInstance(){return INSTANCE;}}

   单例设计模式具备以下特点:

  • 类的构造方法使用 private 修饰,声明为私有,这样就不能在类的外部使用 new 关键字来创建实例对象;
  • 在类的内部创建一个该类的实例对象,并使用静态变量 INSTANCE 引用该对象,由于变量应该禁止外界直接访问,因此使用 private 修饰,声明为私有成员;
  • 为了让类的外部能够获得类的实力对象,需要定义一个静态方法 getInstance() ,用于返回该类的实例 INSTANCE,由于方法是静态的,外界可以通过 " 类名 . 方法名 " 的方式访问。

   单例设计模式的两种形式:

  • 饿汉式(先初始化对象):如上示例,建议使用这种形式。
  • 懒汉式(对象是方法被调用时,才初始化,也叫对象的延迟加载):

class Single{private static Single s = null;private Single(){}public Single getInstance(){if(s == null)s = new Single();return s;}}

五、内部类


   当描述事物时,事物内部还有事务,该事物用内部类来描述。因为内部事物在使用外部事物的内容。例如定义一个描述人的类,而心脏属于人类的一部分,它又有自己的功能描述,所以这时可以在描述人的类中定义一个描述心脏的类,也就是内部类。

   在 Java 中,允许在一个类的内部定义类,这样的类被称为内部类,这个类所在的类被称为外部类。

   编译时,如果代码中有内部类,生成的 class 文件中会包含 Test$1.java 这样的文件,编译器会把内部类翻译成用 $(美元符号)分隔外部类名和内部类名的常规文件,这时内部类的一种编译现象。

   根据内部类的位置、修饰符和定义的方式可以分为成员内部类、静态内部类、方法内部类。

1、成员内部类

   在一个类中除了可以定义成员变量、成员方法,还可以定义类,这样的类被称作成员内部类。

class Outer{private int num = 4;public void test(){Inner inner = new Inner();inner.show();}class Inner{void show(){System.out.println("num"+num);}}}public class Example{Outer outer = new Outer();outer.test();}

   如果想通过外部类去访问内部类,则需要通过外部类对象去创建内部类对象,创建内部类对象的具体语法格式如下:

  • 外部类名 . 内部类名   变量名   =   new  外部类名() . new  内部类名();

public class Example{    public static void main(String[] args){        Outer.Inner inner = new Outer().new Inner();        inner.show();    }}

2、静态内部类

   可以使用 static 关键字来修饰一个成员内部类,该内部类被称作静态内部类,他可以在不创建外部类对象的情况下被初始化,创建静态内部类对象的具体语法格式如下:

  • 外部类名 . 内部类名  =  new  外部类名 . 内部类名();

class Outer{private static int num = 4;static class Inner{void show(){System.out.println("num="+num);}}}public class Example{public static void main(String[] args){Outer.Inner inner = new Outer().Inner();inner.show();}}

    注意:
  • 在静态内部类中只能访问外部类的静态成员;
  • 在静态内部类中可以定义静态成员,而在非静态的内部类中不允许定义静态成员,

3、方法内部类

   方法内部类是指在成员方法中定义的类,它只能在当前方法中 被使用。

  • 不可以被成员修饰符修饰,如 public、private、static等,它的作用域被限定在当前方法中;
  • 可以直接访问外部类的成员,因为还持有外部类的引用。

class Outer{private int num = 4;public void test(){class Inner{void show(){System.out.println("num="+num);}}Inner in = new Inner();in.show();}}public class Example{public static void main(String[] args){Outer out = new Outer();out.test();}}

六、匿名内部类


1、含义

   匿名内部类就是内部类的简写形式。

2、定义内部类的前提

   内部类必须继承类或者实现接口。但是有一个特殊情况,因为所有类都有一个父类 Object,所以在定义时也可以使用 Object。

3、匿名内部类的格式

   new   父类 (参数列表)或 父接口(){

         //匿名内部类实现部分

   }

4、匿名内部类的利弊

   好处:简化书写 。

   坏处:

  • 不能直接调用自己的特有方法;
  • 不能做强转动作;
  • 如果继承的父类或接口中有很多方法时,使用匿名内部类阅读性非常差,且调用麻烦。(定义匿名内部类,一般方法不超过 3 个。)

interface Inter  {      void method();  }  class InnerClassTest   {      public static void main(String[] args)       {          show(new Inter()          {              public void method()              {                  System.out.println("method show run");              }          });      }        public static void show(Inter in)      {          in.method();      }  }

5、Object 类

  在 JDK 中提供了一个 Object 类,它是所有类的父类,即每个类都直接或间接继承自该类。Object 类中的方法如下:

  • getClass().getName():代表返回对象所属类的类名;
  • hashCode():代表该对象的哈希值;
  • Integer.toHexString(hashCode()):代表将对象的哈希值用十六进制表示。

七、Java 的帮助文档


   Java 语言支持三种方式的注释,其中一种被称为文档注释,以 /** 开头,以 */ 结束。文档注释是嵌入到程序中的帮助信息,用于说明如何使用当前程序。Java 中提供了 javadoc 命令,它可以将这些帮助信息提取出来,自动生成 HTML 格式的帮助文档,从而实现程序的文档化。开发者可以查看帮助文档了解程序的功能,而不需要查看程序的源代码,因此可以大大提高开发效率。

/*** Title:Person类* Description:通过Person类来说明Java中的文档注释* Company:Itcast* @author Itcast* @version 1.0*/public class Person{public String name;/*** 这是Person类的构造方法* @param name Person的名字*/public Person (String name){//执行语句;}/*** 这是read()方法的说明* @param bookName 读的书名* @param time 读书的时间* @return 读书数量*/public int read(String bookName,int time){//执行语句;}}

   在文档注释中出现的 @ 标记都是有特殊作用的,具体解释如下:

  • @author:用于对类的说明,表示这个程序的作者;
  • @version:用于对类说明,表示这个程序的开发版本;
  • @param:用于对方法的说明,表示方法定义的参数以及参数对应的说明;
  • @return:用于对方法的说明,表示方法的返回值代表的意义。

   为程序添加文档注释后,便可以使用 javadoc 命令生成 Person 类的帮助文档。打开命令行窗口,进入程序所在的目录,输入生成文档命令:

  • javadoc  -d  .  -version  -author  Person.java

        其中:

                  >  -d  用来指定输出文档存放的目录;

                  >  .  表示当前的目录;

                  >  -version  用来指定输出文档中需要包含版本的信息;

                  >  -author  用来指定输出文档需包含的作者信息;

0 0