三.面向对象(一)


转载自:

1.面向对象(一)

面向过程与面向对象的区别(蛋炒饭VS盖饭)

为什么会出现面向对象分析方法?

因为现实世界太复杂多变,面向过程的分析方法无法满足。

面向过程

采用面向过程必须了解整个过程,每个步骤都有因果关系,每个因果关系都构成了一个步骤,多个步骤就构成了一个系统,因为存在因果关系每个步骤很难分离,非常紧密,当任何一步骤出现问题,将会影响到所有的系统。如:采用面向过程生产电脑,那么他不会分CPU、主板和硬盘,它会按照电脑的工作流程一次成型。代码间耦合度(代码间的关联)强,牵动任何一个因果关系会影响整个系统的运行。

面向对象

面向对象对会将现实世界分割成不同的单元(对象),实现各个对象,如果完成某个功能,只需要将各个对象协作起来就可以。

1】(了解)面向对象  vs 面向过程   

例子:人开门;把大象装冰箱

理解一:人开门

//面向过程:人 打开 门
//面向对象:
人{
  打开(门){ 门.开开(); }
}
门{   开开(){ } }

理解二:人把大象装进冰箱

//面向过程:1)打开冰箱2)把大象放进去 3)关闭冰箱门
//面向对象:
人{
  打开(冰箱){冰箱.开开();}
  操作(大象){大象.进入(冰箱)}
  关闭(冰箱){冰箱.合上()}
}

大象{
  进入(冰箱){}
}

冰箱{
  开开(){}
  合上(){}
}

2】面向对象的编程关注于类的设计!

1)一个项目或工程,不管多庞大,一定是有一个一个类构成的。

2)类是抽象的,好比是制造汽车的图纸。

而具体的一辆一辆的车,是根据图纸制造的,实际上就是类的实例化

3】完成一个项目(或功能)的思路

1)所要完成的功能对应的类的对象是否存在。

2)若存在,则通过对象直接调用对应的类中的属性或方法即可

3)若不存在,需要创建类的对象。甚至说,类都不存在,就需要设计类。

4】面向对象编程的三条主线:

1)类及类的构成成分:属性  方法 构造器  代码块 内部类

2)面向对象编程的三大特征:封装性  继承性 多态性  (抽象性)

3)其它的关键字:this super package import static final abstract interface ...

5】从软件的开发的生命周期来看,基于面向对象可以分为三个阶段:

1)OOA(面向对象的分析)

2)OOD(面向对象的设计)

3)OOP(面向对象的编程)-----Java 就是一个纯面向对象的语言

1.1类

l  类(class)和对象(object)是面向对象的核心概念。

  • 类是对一类事物描述,是抽象的、概念上的定义;对现实世界中具有共性的事物进行抽象就形成了类;类是一种引用类型;类在现实世界中是不存在的,是人们大脑抽象出来的一个概念。
  • 对象是实际存在的该类事物的每个个体,因而也称实例(instance)。
  • “万事万物皆对象”

1.1.2 类及类的成员

类型修饰符  class  类名 extends 父对象名称 implements 接口名称{
       属性声明;     
       方法声明;
}
 

说明:修饰符public:类可以被任意访问。类的正文要用{  }括起来

public class Person{
  //声明私有变量 age
  private int age ;              
  //声明方法showAge()
  public void showAge(int i) { 
    age = i;
  }
}
 

【创建Java自定义类的步骤】

①定义类(考虑修饰符、类名)

②编写类的属性(考虑修饰符、属性类型、属性名、初始化值)

③编写类的方法(考虑修饰符、返回值类型、方法名、形参等)

1.1.4 类的成员之一:属性

语法格式:

修饰符  返回值类型  方法名 (参数列表) {
       方法体语句;
}

说明:修饰符:public, private等。返回值类型:return语句传递返回值。没有返回值:void。

public class Person{
    private int age;
  //声明方法getAge
    public int getAge()  { return age; } 
  //声明方法setAge
    public void setAge(int i) {          
  //将参数i的值赋给类的成员变量age
         age = i;        
  }
}
 

1.1.6 类的成员之三:构造方法(构造器、构造函数,Constructor)

在一个类中,类中的方法可以直接访问类中的成员变量(例外:static方法访问非static,编译不通过)。在不同类中,先创建要访问类的对象,再用对象访问类中定义的成员。

1.1.8 类的内存

1.2.1 对象的创建和使用

当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值。除了基本数据类型之外的变量类型都是引用类型,如下面的Person及前面讲过的数组。

class Person{
  int age;
  void shout(){
    System.out.println(“oh,my god! I am ” + age);
  }
}

Person p1 = new Person();//执行完后的内存状态

1.2.3 对象的使用

1.2.5 对象的内存结构

①我们也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象。

如:new Person().shout();

②使用情况

如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。我们经常将匿名对象作为实参传递给一个方法调用。

1.3再谈方法

①方法是类或对象行为特征的抽象,也称为函数。

②Java里的方法不能独立存在,所有的方法必须定义在类里。

修饰符 返回值类型 方法名(参数类型 形参1,参数类型 形参2,….){

                                          程序代码

                                          return 返回值;

形式参数:在方法被调用时用于接收外部传入的数据的变量。

参数类型:就是该形式参数的数据类型。

返回值:方法在执行完毕后返还给调用它的程序的数据。

返回值类型:方法要返回的结果的数据类型。

实参:调用方法时实际传给函数形式参数的数据。

思考:如何理解方法返回值类型为void的情况 ?

1.3.2 方法的调用

要求:

①同一个类中

②方法名必须相同

③方法的参数列表不同(个数、类型或顺序不同)

 

注意:方法的重载与方法的返回值类型没有关系!

【eclipse快捷键】

1.单行注释:Ctrl +/,再次取消。

2.多行注释:Ctrl+shift +/,Ctrl+shift +\(反斜杠)取消。

3.格式化:Ctrl+shift+F

1.3.4 可变个数的形参的方法

好书推荐:深入java虚拟机第二版(重点第五章)

 

 

//对象没有更多的引用指向,则变成垃圾.

public class OOTest03{

       public static void main(String[] args){

              //u1是引用,保存内存地址指向堆中的对象。

              User u1 = new User();

              //程序执行到此处,u1不再指向堆中的对象。

       //对象变成了垃圾。

              u1 = null;

              //使用一个空的引用去访问成员,会出现什么问题?

              //System.out.println(u1.name); //java.lang.NullPointerException (空指针异常)

              Star s = new Star();

              s = null;

              s.sing(); //java.lang.NullPointerException

       }

class Star{

       //成员方法

       public void sing(){

              System.out.println("Sing a song!");

       }

1.3.6 Java的值传递机制

1.5.1 this是什么?

①this可以用在成员方法中。

②this可以用来区分成员变量和局部变量:

当局部变量(形参)和成员变量重名的时候,如果在方法内部需要使用成员变量,必须

添加this来表明该变量时类成员。

③this可以用在构造方法中。

在构造方法中使用“this(形参列表)”显式的调用本类中重载的其它的构造器(用一个构造方法调用另一个构造方法)。

语法:this(实参);

目的:代码重用。

要求:“this(形参列表)”要声明在构造器的首行!

注意:若一个类中有n个构造器,那么最多有n-1个构造器中使用了this(形参)。

1.5.3理解“this”

public class ThisTest02{

       public static void main(String[] args){

              //创建对象

              Employee e = new Employee(7369,"SMITH");

              //工作

              e.work();

              //创建对象

              Employee e1 = new Employee(7370,"FORD");

              //工作

              e1.work();

              e.m1();

       }

class Employee{

       //员工编号

       int empno;

       //员工名

       String ename;

       //Constructor

       Employee(){}

       Employee(int _empno,String _ename){

              empno = _empno;

              ename = _ename;

       }

       //提供一个员工工作的方法.

       //this用在成员方法中,谁去调用这个成员方法,this就代表谁。

       //this指的就是当前对象。

       public void work(){

              System.out.println(this.ename + "在工作");

              //System.out.println(ename + "在工作"); //this. 可以省略

       }

       //成员方法

       public void m1(){

              this.m2();

              m2();

       }

       //成员方法

       public void m2(){

              System.out.println("TESTING");

       }

1.5.5 this用来区分成员变量和局部变量。

静态方法的执行根本不需要java对象的存在。直接使用 类名.  的方式访问。而this代表的是当前对象。所以静态方法中根本没有this。

public class ThisTest04{

       String str;

       //入口

       public static void main(String[] args){

              Person.m1();

              //str是一个成员变量,必须由引用.  ”访问

              //System.out.println(str);

              ThisTest04 tt = new ThisTest04();

              System.out.println(tt.str); //null

       }

class Person{

       //Field

       String name;

       //Constructor

       Person(){}

       Person(String name){

              this.name = name;

       }

       //静态方法

       public static void m1(){

              //System.out.println(this.name);

              //如果要想访问name只能:

              Person p1 = new Person("刘德华");

              System.out.println(p1.name);

       }

1.6 static关键字

静态的,可以用来修饰属性、方法、*代码块(或初始化块)、*内部类

1.6.2 static修饰属性(类变量)

static修饰的方法叫做静态方法

①随着类的加载而加载,在内存中也是独一份

②可以直接通过“类.类方法”的方式调用

③内部可以调用静态的属性或静态的方法,而不能调用非静态的属性或方法。反之,非静态的方法是可以调用静态的属性或静态的方法

④静态的方法内是不可以有this或super关键字的!

注意:静态的结构(static的属性、方法、代码块、内部类)的生命周期要早于非静态的结构,同时被回收也要晚于非静态的结构。一般情况下工具类中的方法大部分都是静态方法。静态方法不用创建对象也能直接访问该方法。

public class StaticTest03{

       //成员方法

    //成员方法必须使用“引用.”调用

       public void m1(){  }

       //静态方法

    //可以使用“类名.”方式调用.也可以用“引用.”,即使用的是“引用.”,底层还是用的“类名.”

    //静态方法中不能直接访问非静态数据.

    //静态方法中不能使用this

       public static void m2(){

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

       }

       //入口

       public static void main(String[] args){

              StaticTest03 st = new StaticTest03();

              st.m1();

              m2();

           //静态的方法按照正规的方式访问:“类名.”

       //静态的方法也能用“引用.”访问

              st.m2(); //编译阶段检查出st是StaticTest03类型,编译通过,运行的时候,仍然使用 "StaticTest03."的方式访问。//该方法执行不需要对象。

              //空的引用去访问成员的时候会出现空指针异常。

       //m2方法不是“成员”而是静态的。

       //所以即使引用是空的,也不会报空指针异常。

              StaticTest03 s = null;

              s.m2();

       }

1.6.4 static定义静态语句块

每一次调用构造方法之前会执行一次。实例语句块执行顺序也是自上而下。

public class StaticTest02{

       //静态语句块

       static{

              System.out.println("A");

       }

       //实例语句块

       {

              System.out.println("1");

       }

       {

              System.out.println("2");

       }

       {

              System.out.println("3");

       }

       //构造方法

       StaticTest02(){

              System.out.println("StaticTest02无参数的构造执行!");

       }

       //入口

       public static void main(String[] args){

              //调用构造方法

              new StaticTest02();

              new StaticTest02();

              new StaticTest02();

       }

1.6.6 关于代码的顺序

好书推荐:java与模式

1.7.1 什么是设计模式

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造方法的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。

设计模式从结构上分为三类:创建型、结构性、行为型。

其中最简单的设计模式就是单例了,单例这种模式,尽量少用,也有将其称为“反模式”,缺点是单例模式的类型无法被继承。

单例模式有什么好处

我们知道对象实例创建完成后,会放到堆中,如果堆中的实例过多,将会存在特别多的

垃圾,这样会导致一些问题,如内存溢出等,使用单例模式后,只会创建一个实例,显著减

少对象实例的个数,同时也会提高性能,因为不会频繁的创建对象,这只是他的一个好处,

其他方面项目中再说。总之,为了保证JVM中某一个类型的java对象永远只有一个,为了节省内存的开销。

单例模式的三要素

>在类体中需要具有静态的私有的本类型的变量

>构造方法必须是私有的

>提供一个公共的静态的入口点方法

实现单例模式的两种方式

饿汉式单例:在类加载阶段就创建了对象。

懒汉式单例:用到对象的时候才会创建对象。

public class Singleton{ //懒汉式单例

       //静态变量

       private static Singleton s;

      

       //将构造方法私有化

       private Singleton(){}

      

       //对外提供一个公开获取Singleton对象的方法.

       public static Singleton getInstance(){

             

              if(s==null){ //可能存在线程安全问题的!

                     s = new Singleton();

              }

              return s;

       }

}

public class Customer{ //饿汉式单例模式

       //类加载时只执行一次。

       private static Customer c = new Customer();

       //构造方法私有化

       private Customer(){}

       //提供公开的方法

       public static Customer getInstance(){

              return c;

       }

}

public class Test01{//测试

       public static void main(String[] arg){

              /*

              Singleton s1 = new Singleton();

              Singleton s2 = new Singleton();

              System.out.println(s1==s2);

              */

              Singleton s1 = Singleton.getInstance();

              Singleton s2 = Singleton.getInstance();

              Singleton s3 = Singleton.getInstance();

             

              System.out.println(s1==s2);

              System.out.println(s2==s3);

       }

}

其他饿汉式举例

//饿汉式1

class Bank{

       //1.私有化构造器

       private Bank(){}

       //2.创建类的对象,同时设置为private的,通过公共的来调用,体现封装性

       //4.要求此对象也为static

       private static Bank instance = new Bank();

       //3.此公共的方法,必须为static

       public static Bank getInstance(){

              return instance;     

       }

}

//饿汉式2

class Bank{

       //1.私有化构造器

       private Bank(){}

       //2.创建类的对象,同时设置为private的,通过公共的来调用,体现封装性

       //4.要求此对象也为static

       private static Bank instance = null;

       static{

              instance  = new Bank();      

       }

       //3.此公共的方法,必须为static

       public static Bank getInstance(){

              return instance;     

       }

}

1.8 package和import关键字

包其实就是目录,特别是项目比较大,java 文件特别多的情况下,我们应该分目录管理,在java 中称为分包管理,包名称通常采用小写。

软件包机制:

①为了解决类的命名冲突问题,在类名前加命名空间(包机制)。

②在java中使用package语句定义包.(单包,复包)。

③package语句只能出现在.java源文件的第一行。

④package定义的格式,通常采用公司域名倒叙方式。

例如:com.bjpowernode.oa.system;

  以上包含义:bjpowernode公司开发oa项目,system是oa项目中其中一个模块!

package定义的全格式:公司域名倒叙.项目名.模块名;

⑤完整的类名是带有包名的。

⑥带有package语句的java源文件必须这样编译:javac -d 生成路径 java源文件路径。

⑦运行: java com.bjpowernode.javase.day05.User

package com.bjpowernode.javase.day05;

public class User{

       public static void main(String[] args){

              System.out.println("User's main method execute!");

       }

package com.bjpowernode.javase.day05;

public class Test01{

       public static void main(String[] args){

              User u = new User();

              System.out.println(u); //com.bjpowernode.javase.day05.User@c17164

       }

1.8.2 import

package com;

//import语句可以引入其他类.

//import语句只能出现在package语句之下,class定义的语句之上。

//import com.bjpowernode.javase.day05.User;

import com.bjpowernode.javase.day05.*;

//java.lang;软件包下所有类不需要手动导入。系统自动导入.

import java.util.Date;

public class Test02{

       //入口

       public static void main(String[] args){

              //User.class找不到.

              //User u = new User();

              com.bjpowernode.javase.day05.User u = new com.bjpowernode.javase.day05.User();

              System.out.println(u); //com.bjpowernode.javase.day05.User@c17164

              User u1 = new User();

              System.out.println(u1);

              Object o = new Object();

              System.out.println(o); //java.lang.Object@61de33

              //SUN提供的日期

              Date t = new Date();

              System.out.println(t); //Fri Jul 27 15:00:37 CST 2012

       }

JDK中主要的包介绍

1.java.lang----包含一些Java语言的核心类,如String、Math、Integer、 System和Thread,提供常用功能。

2. java.net----包含执行与网络相关的操作的类和接口。

3. java.io   ----包含能提供多种输入/输出功能的类。

4. java.util----包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数。

5. java.text----包含了一些java格式化相关的类

6. java.sql----包含了java进行JDBC数据库编程的相关类/接口

7. java.awt----包含了构成抽象窗口工具集(abstract window toolkits)的

                             多个类,这些类被用来构建和管理应用程序的图形用户界 

                             面(GUI)。

8. java.applet----包含applet运行所需的一些类。

总结

1.面向对象思想的落地法则一

①设计类,并设计类的成员(成员变量&成员方法)

②通过类,来创建类的对象(也称作类的实例化)

③通过“对象.属性” 或“对象.方法”来调用,完成相应的功能

2.创建的多个对象,彼此各自拥有一套类的属性。

当对其中一个对象的属性进行修改时,不会影响到其他对象的属性值。

public class Zoo{

  public static void main(String args[]){

Animal xb=new Animal();

Animal xh=new Animal();

xb.legs=4;

xh.legs=0;

System.out.println(xb.legs);   //4

System.out.println(xh.legs);   //0

xb.legs=2;

System.out.println(xb.legs);   //2

System.out.println(xh.legs);   //0

  }

}

3.类的属性(成员变量)

成员变量vs局部变量

相同点:

①遵循变量声明的格式: 数据类型 变量名 = 初始化值

②都有作用域

不同点:

①声明的位置的不同 :

成员变量:声明在类里,方法外;局部变量:声明在方法内,方法的形参部分,代码块内

②关于修饰符:

成员变量的修饰符有四个:public private protected 缺省;

局部变量没有修饰符,与所在的方法修饰符相同。

③初始化值:一定会有初始化值。

成员变量:如果在声明的时候,不显式的赋值,那么不同数据类型会有不同的默认初始化值。

byte short int long ==>0

float double ==>0.0

char ==>空格

boolean ==>false

引用类型变量==>null

局部变量:一定要显式的赋值(局部变量没有默认初始化值)。

④二者在内存中存放的位置不同:

成员变量:存在于堆空间中;局部变量:栈空间中  。      

4.关于变量的分类:

①按照数据类型的不同:基本数据类型(8种)& 引用数据类型

②按照声明的位置的不同:成员变量 & 局部变量

5.类的方法:提供某种功能的实现

①实例

public void eat(){//方法体}

public String getName(){}

public void setName(String n){}

格式:权限修饰符 返回值类型(void:无返回值/具体的返回值) 方法名(形参){}     

②关于返回值类型

void表明此方法不需要返回值

有返回值的方法:在方法的最后一定有return + 返回值类型对应的变量

记忆:void 与return不可以同时出现一个方法内。像一对“冤家”。

③方法内可以调用本类的其他方法或属性,但是不能在方法内再定义方法!

6.类的初始化的内存解析

内存划分的结构:理解的基础上,学会基本的创建的类的对象在内存中的运行。

①栈(stack):局部变量 、对象的引用名、数组的引用名

②堆(heap):new 出来的“东西”(如:对象的实体,数组的实体),含成员变量

③方法区:含字符串常量

④静态域:声明为static的变量 

7.面向对象思想的落地法则二:(封装性的思想)

①将类的属性私有化

②提供公共的方法(setter & getter)来实现调用

//声明私有变量 age