Java 类&对象


Java 类&对象

初识类和对象

1、类:现实生活中的某种事物的统称;

2、对象:现实生活中的某种事物的实体;

例:车(类)

对象:

宝马

奔驰

法拉利

......等等

面向对象和面向过程比较

1、面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做。

2、面向对象:强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。

面向对象的两个重要概念

1、类:对一类事物的描述,是抽象的、概念上的定义。

2、对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)。

  1. 面向对象程序设计的重点是类的设计
  2. 设计类,就是设计类的成员(field)

例:把大象装进冰箱

面向过程:打开冰箱门->抬起大象放入冰箱->关闭冰箱门
面向对象:分析问题,获取类对象->人、大象、冰箱

人{
	打开(冰箱){
		冰箱.开开();
	}
	装(大象){
		大象.进入();
	}
	关闭(冰箱){
		冰箱.闭合();
	}
}

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

大象{
	进入(){
	}
}

类的实例比(创建对象)

1、说明:对象,是由类new出来的,创建出来的。

2、例:房子设计图(类)-> 房子(对象)

3、典型代码:

Person p1 = new Person();

Person p2 = new Person();

Person p3 = p1;//没有新创建一个对象,共用一个堆空间中的对象实体。

类成员

1、属性(field)

  1. 类成员变量

    1.1 直接定义在类的一对{}内

    1.2 可以在声明属性时,指明其权限,使用权限修饰符。

    1.3 封装性:常用的权限修饰符:private、缺省、protected、public

    1.4 类的属性,根据其类型,都默认初始化值。

    整型(byte、short、int、long:0)
    浮点型(float、double:0.0)
    字符型(char:0 (或'\u0000'))
    布尔型(boolean:false)
    引用数据类型(类、数组、接口:null)

    1.5 加载到堆空间中(非static)

  2. 局部变量

    2.1 局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量。

    2.2 不可以使用权限修饰符。

    2.3 没默认初始化值。意味着,我们在调用局部变量之前,一定要显式赋值。特别地:形参在调用时,我们赋值即可。

    2.4 加载到栈空间

2、方法(method)

方法的声明:权限修饰符 返回值类型 方法名(形参列表){
方法体
}
注意:static、final、abstract 来修饰的方法,后面再讲。

  1. return关键字

1.1 使用范围:使用在方法体中

1.2 作用:

? 1.2.1 结束方法

? 1.2.2 针对于返回值类型的方法,使用"return 数据"方法返回所要的数据

1.3 注意点:return关键字后面不可以声明执行语句。

  1. 方法的重载

    2.1 方法重载的概念

定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。

总结:"两同一不同":同一个类、相同方法名参数列表不同,参数个数不同,参数类型不同;

  1. 可变个数形参的方法
public void show(String ... strs){
		for(int i = 0;i < strs.length;i++){
			System.out.println(strs[i]);
		}
	}
  1. java值传递机制

    4.1 传递规则

    ? 如果变量是基本数据类型,此时赋值的是变量所保存的数据值(字面量的值)。

    ? 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。

    4.2 针对于方法的参数概念

    ? 形参:方法定义时,声明的小括号内的参数

    ? 实参:方法调用时,实际传递给形参的数据

3、构造器(construct)

  1. 构造器的作用

    1.1 创建对象

    1.2 初始化对象的信息

  2. 如果没显式的定义类的构造器的话,则系统默认提供一个空参的构造器

  3. 定义构造器的格式:权限修饰符 类名(形参列表){}

  4. 一个类中定义的多个构造器,彼此构成重载

  5. 一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器

  6. 一个类中,至少会有一个构造器。

4、补充:属性的赋值顺序

  1. 默认初始化
  2. 显式初始化
  3. 构造器中初始化
  4. 通过"对象.方法" 或 "对象.属性"的方式,赋值

关键字 1: this package/import

1、this理解为:当前对象 或 当前正在创建的对象

2、为了更好的实现项目中类的管理,提供包的概念

  1. 1 使用package声明类或接口所属的包,声明在源文件的首行

  2. 2 包,属于标识符,遵循标识符的命名规则、规范(xxxyyyzzz)、“见名知意”

  3. 3 每"."一次,就代表一层文件目录。

3、import:导入包

  1. 1 在源文件中显式的使用import结构导入指定包下的类、接口

  2. 2 声明在包的声明和类的声明之间

  3. 3 如果需要导入多个结构,则并列写出即可

  4. 4 可以使用"xxx.*"的方式,表示可以导入xxx包下的所结构

  5. 5 如果使用的类或接口是java.lang包下定义的,则可以省略import结构

  6. 6 如果使用的类或接口是本包下定义的,则可以省略import结构

  7. 7 如果在源文件中,使用了不同包下的同名的类,则必须至少一个类需要以全类名的方式显示。

  8. 8 使用"xxx.*"方式表明可以调用xxx包下的所结构。但是如果使用的是xxx子包下的结构,则仍需要显式导入

  9. 9 import static:导入指定类或接口中的静态结构:属性或方法。

面向对象三大特性:封装 继承 多态

1、访问控制权限修饰符 private 缺省 protected public

  1. 权限从小到大顺序为:private < 缺省 < protected < public

  1. 修饰类的话,只能使用:缺省、public

2、派生类 extends(提高代码的复用性)

  1. 继承性的格式:

    class A extends B{}

    A:子类、派生类、subclass

    B:父类、超类、基类、superclass

  2. 类继承父类以后有哪些不同?

    1. 1 体现:一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。

    特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私的结构。只因为封装性的影响,使得子类不能直接调用父类的结构而已。

    1. 2 子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。子类和父类的关系,不同于子集和集合的关系。
  3. Java中继承性的说明

    1. 1 一个类可以被多个子类继承。

    2. 2 Java中类的单继承性:一个类只能有一个父类

    3. 3 子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类

    4. 4 子类继承父类以后,就获取了直接父类以及所间接父类中声明的属性和方法

  4. java.lang.Object类的理解

    1. 1 如果我们没显式的声明一个类的父类的话,则此类继承于java.lang.Object类

    2. 2 所有java类(除java.lang.Object类之外都直接或间接的继承于java.lang.Object类,所的java类具有java.lang.Object类声明的功能

  5. 方法的重写(运行后绑定)

    1. 1 什么是方法的重写(override 或 overwrite)?

    ? 子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作。

  6. super关键字

    1. 1 通过使用"super.属性"或"super.方法"的方式,显式的调用父类中声明的属性或方法;

    2. 2 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的是父类中声明的属性;

    3. 3 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法。

  7. 子类对象实例化过程

    this(...) 或 super(...) 或 super()

3、一种事物的多种形态,抽象概念(多态)

  1. 何为多态性?

    对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)

    举例:

    Person p = new Man();

    Object obj = new Date();

  2. 多态性的使用:虚拟方法调用

    1. 1 有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。

    总结: 编译,看左边;运行,看右边。

  3. 多态性使用的注意点

对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)

  1. 关于向上转型与向下转型(instanceof

    1. 1 a instanceof A : 判断对象 a 是否是类A的实例。如果是,返回true;如果不是,返回false。

    2. 2 如果 a instanceof A 返回true,则 a instanceof B 也返回true. 其中,类B是类A的父类。

4、Object类的使用

  1. java.lang.Object类的说明

  2. 1 Object类是所有Java类的根父类

  3. 2 如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类

  4. 3 Object类中的功能(属性、方法)具有通用性。

属性:无

方法:equals()/toString()/getClass()/hashCode()/clone()/finalize()/wait()/notify()/notifyAll()

  1. 4 Object类只声明了一个空参的构造器

  2. equals()方法

    1. 1 equals()的使用:

      1. 1.1 是一个方法,而非运算符

      2. 1.2 只能适用于引用数据类型

      3. 1.3 Object类中equals()的定义

      public boolean equals(Object obj) {
      	        return (this == obj);
      	  }
      

      说明:Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同。(即两个引用是否指向同一个对象实体)

  3. 像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。

  4. 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们就需要对Object类中的equals()进行重写。重写的原则是比较两个对象的实体内容是否相同。

5、单元测试

Java中的JUnit单元测试

  1. 中当前工程 - 右键择:build path - add libraries - JUnit 4 - 下一步
  2. 创建Java类,进行单元测试。

此时的Java类要求: 2.1此类是public的;2.2此类提供公共的无参的构造器

  1. 此类中声明单元测试方法。

此时的单元测试方法:方法的权限是public,没返回值,没形参

  1. 此单元测试方法上需要声明注解:@Test

    并在单元测试类中导入:import org.junit.Test;

  2. 声明好单元测试方法以后,就可以在方法体内测试相关的代码。

  3. 写完代码以后,左键双击单元测试方法名,右键:run as - JUnit Test

6、包装类

基本数据类型<--->包装类:JDK 5.0 新特性:自动装箱与自动拆箱

基本数据类型、包装类--->String:调用String重载的valueOf(Xxx xxx)

String--->基本数据类型、包装类:调用包装类的parseXxx(String s)

注意:转换时,可能会报NumberFormatException

关键字 2: static final abstract interface

static:静态的

  1. 可以用来修饰的结构:主要用来修饰类的内部结构

    属性、方法、代码块、内部类

  2. static修饰属性:静态变量(或类变量)

    1. 1 属性,是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)

      实例变量:我们创建了类的多个对象,每个对象都独立的拥一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。

      静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。

    2. 2 static修饰属性的其他说明:

      1. 2.1 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用;

      2. 2.2 静态变量的加载要早于对象的创建。

      3. 2.3 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。

      4. 2.4 类变量 实例变量

        ? 类 yes no

        ? 对象 yes yes

  3. static修饰方法:静态方法、类方法

    1. 1 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用

    2. 2 静态方法 非静态方法

      ? 类 yes no

      ? 对象 yes yes

    3. 3 静态方法中,只能调用静态的方法或属性;非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性。

  4. static的注意点:

    1. 1 在静态的方法内,不能使用this关键字、super关键字

    2. 2 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。

  5. 如何判定属性和方法应该使用static关键字

    1. 1 关于属性

      属性是可以被多个对象所共享的,不会随着对象的不同而不同的。

      类中的常量也常常声明为static

    2. 2 关于方法

      操作静态属性的方法,通常设置为static的;

      工具类中的方法,习惯声明为static的。比如:Math、Arrays、Collections类

单例模式

1、饿汉式

class Bank{
	//1.私化类的构造器
	private Bank(){
		
	}
	//2.内部创建类的对象
	//4.要求此对象也必须声明为静态的
	private static final Bank instance = new Bank();
	
	//3.提供公共的静态的方法,返回类的对象
	public static Bank getInstance(){
		return instance;
	}
}

2、懒汉式

class Order{
	//1.私化类的构造器
	private Order(){
		
	}
	//2.声明当前类对象,没初始化
	//4.此对象也必须声明为static的
	private static Order instance = null;
	//3.声明public、static的返回当前类对象的方法
	public static Order getInstance(){
		if(instance == null){
			instance = new Order();	
		}
		return instance;
	}
}

main()方法的说明

小结:一叶知秋

public static void main(String[] args){//方法体}

权限修饰符:private 缺省 protected pubilc ---->封装性

修饰符:static \ final \ abstract \native 可以用来修饰方法

返回值类型: 无返回值 / 有返回值 -->return

方法名:需要满足标识符命名的规则、规范;"见名知意"

形参列表:重载 vs 重写;参数的值传递机制;体现对象的多态性

方法体:来体现方法的功能

代码块

1、代码块的作用:用来初始化类、对象的信息

2、分类:代码块要是使用修饰符,只能使用static

3、实例化子类对象时,涉及到父类、子类中静态代码块、非静态代码块、构造器的加载顺序:由父及子,静态先行。

4、静态代码块

  1. 1 内部可以输出语句

  2. 2 随着类的加载而执行,而且只执行一次

  3. 3 作用:初始化类的信息

  4. 4 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行

  5. 5 静态代码块的执行要优先于非静态代码块的执行

  6. 6 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构

5、非静态代码块

  1. 1 内部可以输出语句

  2. 2 随着对象的创建而执行

  3. 3 每创建一个对象,就执行一次非静态代码块

  4. 4 作用:可以在创建对象时,对对象的属性等进行初始化

  5. 5 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行

  6. 6 非静态代码块内可以调用静态的属性,静态的方法、或非静态的属性、非静态的方法

final 最终的

1、final 用来修饰一个类:此类不能被其他类所继承。

? 比如:String类、System类、StringBuffer类

2、final 用来修饰方法:表明此方法不可以被重写

? 比如:Object类中getClass();

3、final 用来修饰变量:此时的"变量"就称为是一个常量

  1. final修饰属性:可以考虑赋值的位置:显式初始化、代码块中初始化、构造器中初始化;
  2. final修饰局部变量:尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。

4、static final 用来修饰属性:全局常量

abstract 抽象的

1、可以用来修饰:类、方法

2、具体的:

  1. 1 abstract修饰类:抽象类

    此类不能实例化、抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作,抽象的使用前提:继承性

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

    抽象方法只有方法的声明,没方法体,包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。若子类重写了父类中的所有的抽象方法后,则此子类方可实例化,若子类没重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰;

3、注意点

  1. abstract不能用来修饰:属性、构造器等结构
  2. abstract不能用来修饰私方法、静态方法、final的方法、final的类

interface 接口

理解:修饰接口:public、abstract(本质上一质)、缺省的

1、接口使用interface来定义;

2、Java中,接口和类是并列的两个结构

3、如何定义接口:定义接口中的成员

  1. 1 JDK7及以前:只能定义全局常量和抽象方法

    ? 全局常量:public static final可以省略不写

    ? 抽象方法:public abstract可以省略不写

  2. 2 JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)

4、接口中不能定义构造器的!意味着接口不可以实例化

5、Java开发中,接口通过让类去实现(implements)的方式来使用;

  1. 1 如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化

  2. 2 如果实现类没覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类

6、Java类可以实现多个接口,弥补了Java单继承性的局限性;

? 格式:class AA extends BB implements CC,DD,EE

7、接口与接口之间可以继承,而且可以多继承

类结构:内部类(类的第五个成员)

1、定义:Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类。

2、内部类的分类:

  1. 1 成员内部类(静态、非静态 )

  2. 2 局部内部类(方法内、代码块内、构造器内)

3、成员内部类的理解:

  1. 1 一方面,作为外部类的成员:调用外部类的结构;可以被static修饰;可以被4种不同的权限修饰;

  2. 2 另一方面,作为一个类:类内可以定义属性、方法、构造器等;可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承;可以被abstract修饰;

4、成员内部类:

  1. 1 如何创建成员内部类的对象?(静态的,非静态的)

    //创建静态的Dog内部类的实例(静态的成员内部类):

    Person.Dog dog = new Person.Dog();

    //创建非静态的Bird内部类的实例(非静态的成员内部类):

    //Person.Bird bird = new Person.Bird();//错误的

    Person p = new Person();

    Person.Bird bird = p.new Bird();

  2. 2 如何在成员内部类中调用外部类的结构?

class Person{
	String name = "小明";
public void eat(){
}
//非静态成员内部类
	class Bird{
		String name = "杜鹃";
		public void display(String name){
			System.out.println(name);//方法的形参
			System.out.println(this.name);//内部类的属性
			System.out.println(Person.this.name);//外部类的属性
		//Person.this.eat();//外部类方法
		}
	}
}

5、局部内部类的使用:

//返回一个实现了Comparable接口的类的对象
	public Comparable getComparable(){
		//创建一个实现了Comparable接口的类:局部内部类
		//方式一:
//		class MyComparable implements Comparable{
//			@Override
//			public int compareTo(Object o) {
//				return 0;
//			}	
//		}	
//		return new MyComparable();
		//方式二:
		return new Comparable(){
			@Override
			public int compareTo(Object o) {
				return 0;
			}	
		};	
	}

6、注意点:局部内部类是指位于方法内的类,局部内部类若要访问其所在方法内的变量,则该变量必须是final修饰的。

总结:成员内部类和局部内部类,在编译以后,都会生成字节码文件。

格式:成员内部类:外部类$内部类名.clas

? 局部内部类:外部类$数字内部类名.class

匿名对象(我们创建的对象,没显式的赋给一个变量名)

特点:匿名对象只能调用一次。

举例:

new Phone().sendEmail();

new Phone().playGame();

new Phone().price = 1999;

new Phone().showPrice();//0.0

应用场景:

PhoneMall mall = new PhoneMall();

//匿名对象的使用

class PhoneMall{
public void show(Phone phone){
	phone.sendEmail();
	phone.playGame();
}
}
mall.show(new Phone());