03 Java面向对象程序开发

完成一个项目(或功能)的思路
1)所要完成的功能对应的类的对象是否存在。
2)若存在,则通过对象直接调用对应的类中的属性或方法即可
3)若不存在,需要创建类的对象。甚至说,类都不存在,就需要设计类。

面向对象编程的三条主线
1)类及类的构成成分:属性 方法 构造器 代码块 内部类
2)面向对象编程的特征:封装性 继承性 多态性 (抽象性)
3)其它的关键字:this super package import static final abstract interface …

1. 类的成分

类的组成成分

  1. 属性(成员变量,Field)
  2. 方法(成员方法,函数,Method)

构造器
构造器的作用:①创建对象 ②给创建的对象的属性赋值

  1. 设计类时,若不显式声明类的构造器的话,程序会默认提供一个空参的构造器;
  2. 一旦显式的定义类的构造器,那么默认的构造器就不再提供;
  3. .如何声明类的构造器。格式:权限修饰符 类名(形参){ }
  4. 类的多个构造器之间构成重载

类对象的属性赋值的先后顺序:
①属性的默认初始化 ②属性的显式初始化③通过构造器给属性初始化
④通过"对象.方法"的方式给属性赋值

代码块:是类的第4个成员
作用:用来初始化类的属性
分类:只能用static来修饰。

  • 静态代码块:
  • 1.里面可以有输出语句
  • 2.随着类的加载而加载,而且只被加载一次
  • 3.多个静态代码块之间按照顺序结构执行
  • 4.静态代码块的执行要早于非静态代码块的执行。
  • 5.静态的代码块中只能执行静态的结构(类属性,类方法)
  • 非静态代码块:
  • 1.可以对类的属性(静态的 & 非静态的)进行初始化操作,同时也可以调用本类声明的方法(静态的 & 非静态的)
  • 2.里面可以有输出语句
  • 3.一个类中可以有多个非静态的代码块,多个代码块之间按照顺序结构执行
  • 4.每创建一个类的对象,非静态代码块就加载一次。
  • 5.非静态代码块的执行要早于构造器

内部类 * 类的第5个成员:

  • 1.相当于说,我们可以在类的内部再定义类。外面的类:外部类。里面定义的类:内部类

  • 2.内部类的分类:成员内部类(声明在类内部且方法外的) vs 局部内部类(声明在类的方法里)

  • 3.成员内部类:

  •  3.1是外部类的一个成员:①可以有修饰符(4个)②static final ③可以调用外部类的属性、方法
    
  •  3.2具体类的特点:①abstract ②还可以在其内部定义属性、方法、构造器
    
  • 4.局部内部类:

  • 5.关于内部类,大家掌握三点:

  • ①如何创建成员内部类的对象(如:创建Bird类和Dog类的对象)

  • ②如何区分调用外部类、内部类的变量(尤其是变量重名时)

  • ③局部内部类的使用 (见TestInnerClass1.java)

2. 类的初始化 (创建类的对象)

3. 面向对象的三大特性

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

1. 封装性的思想:对象有明确的边界,对边界内部起保护作用
通俗来说:尽可能的隐藏对象内部的实现细节,控制用户对对象的修改及访问权限

  1. 将类的属性私有化;
  2. 提供公共的方法(setter & getter)来实现调用

四种权限都可以用来修饰属性、方法、构造器:
03 Java面向对象程序开发
2. 继承性的思想 : 通过"class A extends B"类实现类的继承

继承一个已经存在的类时,就可以复用这个类的方法和字段,同时可以在新类中添加新的方法和字段。
注意:构造方法不能继承!

3. 多态性的思想 :父类引用指向子类对象

对象的多态性:可以直接应用在抽象类和接口上
有2中表现方式:①.重载,重写;②.子类对象的多态性
使用的前提:①要有继承关系; ②要有方法的重写

格式:Person p = new Man();//向上转型
// 虚拟方法调用:通过父类的引用指向子类的对象实体,当调用方法时,实际执行的是子类重写父类的方法
p1.eat();
p1.walk();
// p1.entertainment();

关于向下转型:

①向下转型,使用强转符:()
②为了保证不报ClassCastException,在向下转型前,进行判断:instanceof

		// 若a是A类的实例,那么a也一定是A类的父类的实例。
		if (p1 instanceof Woman) {
			System.out.println("hello!");
			Woman w1 = (Woman) p1;
			w1.shopping();
		}

		if (p1 instanceof Man) {
			Man m1 = (Man) p1;
			m1.entertainment();
		}

4. 重载和重写

方法的重载(overload)

要求 :同一个类中 2.方法名必须相同 3.方法的参数列表不同(①参数的个数不同②参数类型不同)
补充 :方法的重载与方法的返回值类型没有关系!

方法的重写(override)
子类用特殊的方法实现,替换掉父类继承给它的方法实现

【面试题】方法的重载与重写的区别?
重载:“两同一不同”:同一个类,同一个方法名,不同的参数列表。 注:方法的重载与方法的返回值无关!构造器是可以重载的
重写:(前提:在继承的基础之上,子类在获取了父类的结构以后,可以对父类中同名的方法进行“重构”)方法的返回值,方法名,形参列表形同;访问修饰符比父类 相同或者更宽;子类方法的异常类型不大于父类的;
两个方法要同为static或同为非static。

5. this和super

this
1.使用在类中,可以用来修饰属性、方法、构造器
2.表示当前对象或者是当前正在创建的对象
3.当形参与成员变量重名时,如果在方法内部需要使用成员变量,必须添加this来表明该变量时类成员
4.在任意方法内,如果使用当前类的成员变量或成员方法可以在其前面添加this,增强程序的阅读性
5.在构造器中使用“this(形参列表)”显式的调用本类中重载的其它的构造器

  • 5.1 要求“this(形参列表)”要声明在构造器的首行!
  • 5.2 类中若存在n个构造器,那么最多有n-1构造器中使用了this。

super:
1.super,相较于关键字this,可以修饰属性、方法、构造器
2.super修饰属性、方法:在子类的方法、构造器中,通过super.属性或者super.方法的形式,显式的调用父类的指定属性或方法。尤其是,当子类与父类有同名的属性、或方法时,调用父类中的结构的话,一定要用“super.”
3.通过“super(形参列表)”,显式的在子类的构造器中,调用父类指定的构造器!

任何一个类(除Object类)的构造器的首行,要么显式的调用本类中重载的其它的构造器“this(形参列表)”或显式的调用父类中
指定的构造器“super(形参列表)”,要么默认的调用父类空参的构造器"super()"
建议在设计类时,提供一个空参的构造器!

6. java的值传递机制

1)方法的参数传递

  • 形参:方法声明时,方法小括号内的参数
  • 实参:调用方法时,实际传入的参数的值

2)规则:java中的参数传递机制:值传递机制

  • 形参是基本数据类型的:将实参的值传递给形参的基本数据类型的变量
  • 形参是引用数据类型的:将实参的引用类型变量的值(对应的堆空间的对象实体的首地址值)传递给形参的引用类型变量

案例1:基本数据类型的值传递

/**
 * 基本数据类型值传递
 */
public class TestArgsTransfer {
    public static void main(String[] args) {

        TestArgsTransfer tt = new TestArgsTransfer();
        int i = 10;
        int j = 5;
        System.out.println("i:" + i + " j:" + j);//i : 10  j : 5
        
        tt.swap(i, j);//将i的值传递给m,j的值传递给n
        
        System.out.println("i:" + i + " j:" + j);//i : 10  j : 5

    }
    //定义一个方法,交换两个变量的值
    public void swap(int m,int n) {
        int temp = m;
        m = n;
        n = temp;
        System.out.println("m:" + m + " n:" + n);//m:5 n:10
    }
}

控制台打印效果如下:
03 Java面向对象程序开发

案例2:引用数据类型的值传递

/**
 * 引用数据类型值传递
 */
public class TestArgsTransfer {
    public static void main(String[] args) {

        TestArgsTransfer tt = new TestArgsTransfer();
    DataSwap ds = new DataSwap();

        System.out.println("ds.i:" + ds.i + " ds.j:" + ds.j);

                tt.swap(ds);
                System.out.println("ds:"+ds);

                System.out.println("ds.i:" + ds.i + " ds.j:" + ds.j);

                }
//交换元素的值
public void swap(DataSwap d){
        int temp = d.i;
        d.i = d.j;
        d.j = temp;
        System.out.println("交换元素的值:"+d);//打印引用变量d的值
        }
        }

class DataSwap{
    int i = 10;
    int j = 5;
}

控制台打印效果如下:
03 Java面向对象程序开发

7. 其它关键字

abstract:抽象的,可以用来修饰类、方法

  • 1.abstract修饰类:抽象类

  • 1)不可被实例化

  • 2)抽象类有构造器 (凡是类都有构造器)

  • 3)抽象方法所在的类,一定是抽象类。

  • 4)抽象类中可以没有抽象方法。

  • 当我们设计一个类,不需要创建此类的实例时候,就可以考虑将其设置为抽象的,由其子类实现这个类的抽象方法以后,就行实例化

  • 2.abstract修饰方法:抽象方法

  • 1)格式:没有方法体,包括{}.如:public abstract void eat();

  • 2)抽象方法只保留方法的功能,而具体的执行,交给继承抽象类的子类,由子类重写此抽象方法。

  • 3)若子类继承抽象类,并重写了所有的抽象方法,则此类是一个"实体类",即可以实例化

  • 4)若子类继承抽象类,没有重写所有的抽象方法,意味着此类中仍有抽象方法,则此类必须声明为抽象的!

接口(interface) : 是与类并行的一个概念

  • 1.接口可以看做是一个特殊的抽象类。是常量与抽象方法的一个集合,不能包含变量、一般的方法。
  • 2.接口是没有构造器的。
  • 3.接口定义的就是一种功能。此功能可以被类所实现(implements)。
  • 比如:class CC extends DD implements AA
  • 4.实现接口的类,必须要重写其中的所有的抽象方法,方可实例化。若没有重写所有的抽象方法,则此类仍为一个抽象类
  • 5.类可以实现多个接口。----java 中的类的继承是单继承的
  • 6.接口与接口之间也是继承的关系,而且可以实现多继承
  • 5,6描述的是java中的继承的特点。

  • 7.接口与具体的实现类之间也存在多态性

static修饰属性(类变量):

  • 1.由类创建的所有的对象,都共用这一个属性

  • 2.当其中一个对象对此属性进行修改,会导致其他对象对此属性的一个调用。vs 实例变量(非static修饰的属性,各个对象各自拥有一套副本)

  • 3.类变量随着类的加载而加载的,而且独一份

  • 4.静态的变量可以直接通过“类.类变量”的形式来调用

  • 5.类变量的加载是要早于对象。所以当有对象以后,可以“对象.类变量”使用。但是"类.实例变量"是不行的。

  • 6.类变量存在于静态域中。

  • static修饰方法(类方法):

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

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

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

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

  • 注:静态的结构(static的属性、方法、代码块、内部类)的生命周期要早于非静态的结构,同时被回收也要晚于非静态的结构

final:最终的 ,可以用来修饰类、属性、方法
*

  • 1.final修饰类:这个类就不能被继承。如:String类、StringBuffer类、System类
  • 2.final修饰方法:不能被重写。如:Object类的getClass()
  • 3.final修饰属性:此属性就是一个常量,一旦初始化后,不可再被赋值。习惯上,常量用大写字符表示。
  • 此常量在哪里赋值:①此常量不能使用默认初始化 ②可以显式的赋值、代码块、构造器。
  • 变量用static final修饰:全局常量。比如:Math 类的PI