Java面对对象

类和对象

类:对象行为和状态的抽象描述
对象:类的一个实例

JVM内存结构

存放对象实例;几乎所有的对象实例都在堆区中分配内存

虚拟机栈

存储局部变量等

方法区

存储已经被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等

变量

变量分为:

  1. 成员变量:类中方法外,包括实例变量(non-static)和静态变量(static)
  2. 局部变量:类中方法/代码块中

实例变量 (instance variable) & 局部变量 (local variable)

实例变量局部变量
声明位置类中方法外,没有static修饰类中方法或代码块中 (形参,方法体局部变量,代码块局部变量)
内存储存位置堆区栈区
修饰符权限修饰符等final
初始化有默认值没有默认值,声明后必须初始化才能使用
生命周期对象创建时创建,对象销毁时销毁方法调用时创建,方法运行结束销毁

方法的参数传递机制 (值传递)

基本数据类型:实参给形参传递数据值
引用数据类型:实参给形参传递地址值,两者指向同一个对象

例子:
字符串对象是不可变的

public static void main(String[] args) {
	String str = "hello";
	changeString(str);
	System.out.println(str);	//输出:hello
}

public static void changeString(String s) {
	s = "hi";
}

重载 (Overload)

同一个类中,方法名相同,形参列表不同(类型,数量,顺序);与返回值类型、权限修饰符、形参变量名、方法体无关

可变个数形参

等价于数组类型形参

public void f() {}
public void f(String args) {}
public void f(String ... args) {}	//不能和下面的方法同时存在
//public void f(String[] args) {}	
  1. 调用时可以不传参数或传入多个参数
  2. 可变个数形参必须在参数列表的末尾,且最多只能声明一个可变形参
  3. 和其他同名不同形参列表的方法构成重载
  4. 优先调用形参个数不可变的方法

构造器

  1. 所有的类都有构造器
  2. 如果没有显式声明构造器,编译器会自动添加一个默认的无参构造器(其权限修饰符与类的一致)
  3. 如果显式声明了构造器,编译器不会自动添加默认的无参构造器,按需手动添加
  4. 构造器名称与类名一致,且没有返回值类型

封装 (Encapsulation)

权限修饰符本类本包其他包的子类任意位置使用对象
privateYNNN变量、方法、内部类
defaultYYNN外部类、接口、变量、方法、内部类
protectedYYY/NN变量、方法、内部类
publicYYYY外部类、接口、变量、方法、内部类

protected:

  1. 子类和父类在同一包中:protected成员能被本包中任何其他类访问
  2. 子类和父类不在同一包中:在子类中,子类实例可以访问其从父类继承的protected方法,父类实例不能访问其protected方法

继承 (Inheritance)

  1. 子类继承父类的属性和方法;子类可以通过public修饰的set/get方法来访问父类的私有成员
  2. 子类不继承父类的构造器
  3. 子类在构造器中调用父类的构造器:
    若父类有无参构造器:编译器在子类的构造器中自动调用父类的无参构造器
    若父类没有无参构造器:必须在子类的构造器中显式地通过super(实参列表)调用父类的有参构造器
  4. 单继承,且多重继承

重写 (Override)

子类根据需要重新实现自父类继承来的方法

  1. 方法名不变,参数列表不变
  2. 权限修饰符不能低于父类方法的权限修饰符 (public>protected>default>private) (private方法不能被重写)
  3. 返回值类型可以不同,但必须是父类方法返回值类型的子类

多态 (Polymorphism)

多态是同一个行为具有多个不同表现形式或形态的能力

  1. 必要条件:
    (1)继承
    (2)重写
    (3)父类引用指向子类对象
    Parent p = new Child();
    
  2. 使用多态方式调用方法时:编译看左边父类,运行看右边子类
    编译时,检查父类是否有该方法,如果没有,则编译错误;如果有,执行子类重写后的方法
  3. 向上转型:子类对象赋值给父类变量(自动类型转换)
    向下转型:父类对象赋值给子类变量(强制类型转换),可能导致ClassCastException
  4. instanceof: 返回true/false
    if (对象 instanceof) {} 
    

注意:多态性只适用于方法,不适用于属性

this

表示当前对象或正在创建的对象

  1. this.属性
    区别同名的实例变量和局部变量
  2. this.方法
    调用当前对象的成员方法,可省略“this.”
  3. this()/this(实参列表)
    只能出现在构造器的首行

super

表示父类的

  1. super.属性
    区别同名的子类实例变量和父类实例变量
  2. super.方法
    子类重写了父类的方法,仍需调用父类中被重写的方法
  3. super()/super(实参列表)
    只能出现在子类构造器的首行

非静态代码块

[修饰符] class 类名 {
	{
		非静态代码块
	}
}
  1. 每次创建对象都会执行
  2. 优先于构造器执行

实例初始化

  1. 实例对象创建时执行实例初始化方法
  2. 实例初始化方法:<init>()/<init>(形参列表),是由编译器生成
  3. 实例初始化方法包含三部分:
    (1)实例变量的显式赋值
    (2)非静态代码块
    (3)构造器
    (1)和(2)按顺序执行,(3)最后执行
  4. 一个类有几个构造器,就有几个实例初始化方法
  5. super()/super(形参列表):调用父类的构造器,实际是调用父类的实例初始化方法;只能出现在子类构造器的首行,实际是只能出现在子类实例初始化方法的首行
  6. 先执行父类实例初始化方法,再执行子类实例初始化方法
  7. 如果子类重写了父类的方法,在创建子类对象时,若该方法在父类实例初始化方法中被调用,执行重写后的方法

Object类

Object类是所有类的父类,只有一个空参的构造器
子类可以使用Object的所有方法

  1. public String toString()
    返回“对象运行时的类@对象的hash值的十六进制形式”;通常被重写
  2. public final Class<?> getClass()
    返回对象运行时的类
  3. protected void finalize()
    实例被GC回收时运行
  4. public int hashCode()
    返回对象的hash值,表示在哈希表中的位置
  5. public boolean equals(Object obj)
    比较当前对象this和指定对象obj的内存地址是否相等(等价于“==”)
    如果重写该方法,则必须重写hashCode方法;且重写必须遵循:
    非空性:对于任意非空引用x,x.equals(null) = false
    自反性:x.equals(x) = true
    对称性:x.equals(y) = true,则y.equals(x) = true
    传递性:x.equals(y) = true, y.equals(z) = true,则x.equals(z) = true
    一致性:如果x,y引用的对象没有发生变化,那么重复调用x.equals(y)的结果一致

final

  1. 修饰类:不能被继承
  2. 修饰方法:可以被继承,不能被重写
  3. 修饰变量:必须显式指定初始值,且不能被修改

static

静态方法

  1. 本类中直接使用,其他类中“类名.方法名”调用
  2. 静态方法中不能使用this,super,类的非静态成员(不能直接使用,要先实例化)

静态变量

  1. 静态变量被所有类实例对象共享,仅在类初次加载时初始化一次
  2. 储存在方法区

注意:

  1. 静态变量和静态方法都可以被继承和隐藏而不能被重写,因此不能实现多态
  2. 如果子类重新定义了父类的静态变量和静态方法,则在子类中调用的是子类的静态变量和静态方法;反之,在子类中调用的是父类的静态变量和静态方法

静态代码块

[修饰符] class 类名 {
	static {
		静态代码块
	}
}
  1. 类初始化时执行
  2. 不能使用this,super,非静态成员

类初始化

  1. 类初始化方法:<clinit>(),一个类只有一个,且只执行一次
  2. 类初始化方法包括:
    (1)静态变量的显式赋值
    (2)静态代码块
    (1)和(2)按顺序执行
  3. 先初始化父类,再初始化子类
  4. 先类初始化,再实例初始化

单例模式

一个类只有一个对象实例

  1. 私有的构造器
  2. 类的单个静态实例
  3. 供外界访问该实例的静态方法

饿汉式实现(eager initialization)

类加载时就实例化,线程安全

public class Singleton {
	private Singleton() {}
	
	private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }
}

懒汉式实现(lazy initialization)

线程不安全版:

public class Singleton {
	private Singleton() {}
	
	private static Singleton instance = null;

    public static Singleton getInstance() {
    	if(instance == null) {
			instance = new Singleton();
		}
        return instance;
    }
}

线程安全版:

public class Singleton {
	private Singleton() {}
	
	private static Singleton instance = null;

    public static synchronized Singleton getInstance() {
    	if(instance == null) {
			instance = new Singleton();
		}
        return instance;
    }
}

abstract

抽象类:

[权限修饰符] abstract class 类名 {
}

抽象方法:

[其他修饰符] abstract 返回值类型 方法名(形参列表);  //抽象方法没有方法体
  1. 抽象类不能直接实例化
  2. 抽象类有构造器,供子类实例化中调用
  3. 子类继承抽象类,必须重写所有的抽象方法,否则该子类必须定义为抽象类
  4. 抽象类引用指向其子类对象构成多态
  5. 抽象类可以没有抽象方法;包含抽象方法的类必须声明为抽象类
  6. 抽象类不能被final修饰;抽象方法不能被private,final,static修饰

模板方法模式

public abstract class CalTime {
	public long getTime() {
		long start = System.currentTimeMillis();
		runTask();
		long end = System.currentTimeMillis();
		return end - start;
	}
	abstract void runTask();	//抽象出不确定的部分,由子类具体实现
}
public class MyCalTime extends CalTime {
	void runTask() {
		//方法体
	}
}

接口

[权限修饰符] interface 接口 {
}
[修饰符] class 实现类 implements 接口 {
}

接口的特性

  1. 接口不能实例化,只能被类实现,且一个类可以实现多个接口
  2. 类实现接口时,必须重写所有抽象方法,否则该类必须为抽象类
  3. 接口引用指向其实现类对象构成多态
  4. 接口没有构造方法
  5. 接口支持多继承

接口的成员

Java 8之前:

  1. 变量类型只能是public static final,修饰符均可省略
  2. 方法类型只能是public abstract,修饰符均可省略

Java 8之后:

  1. 可以有包含具体实现的静态方法,类型为public static,其中public可省略
  2. 可以有包含具体实现的默认方法,类型为public default,其中public可省略

常用接口

  1. java.lang.Comparable
    抽象方法:int compareTo(T o)
  2. java.util.Comparator
    抽象方法:int compare(T o1, T o2)

代理模式

使用代理对象来控制对真实对象的访问,应用场景:

  1. 安全代理:屏蔽对真实对象的直接访问
  2. 远程代理:通过代理类处理远程方法调用(RMI)
  3. 延迟加载:先加载轻量级代理类对象,需要时再加载真实对象

代理模式有静态代理和动态代理两种实现方式,这里只讨论静态代理

  1. 定义接口及其实现类
  2. 创建代理类并实现该接口
  3. 将目标对象注入代理类,在代理类的实现方法中调用目标类的对应方法
//接口
public interface Network {
	void connect();
}
//目标类
public class Server implements Network {
	public void connect() {
		System.out.println("connect network");
	}
}
//代理类
public class ProxyServer implements Network {
	private Server server;
	public ProxyServer(Server server) {
		this.server = server;
	}
	public void connect() {
		System.out.println("before connect");
		server.connect();
		System.out.println("after connect");
	}
}
//实际使用
public class Main {
    public static void main(String[] args) {
        ProxyServer proxyServer = new ProxyServer(new Server());
        proxyServer.connect();
    }
}

内部类

成员内部类和局部内部类编译后都会生成相应的字节码文件(.class)

成员内部类

  1. 作为外部类的成员:
    (1)可以访问外部类的其他成员
    (2)可以用static修饰
    (3)可以用4种权限修饰符修饰
  2. 作为一个类:
    (1)类中可以定义属性,方法,构造器等
    (2)可以用final修饰
    (3)可以用abstract修饰
静态内部类
class OutClass {
	static class InClass {
		static void f1() {}
		void f2() {}
	} 
}
  1. 可以有静态变量和静态方法/代码块
  2. 不能直接访问外部类的非静态成员
  3. 在外部类的外面访问静态内部类的成员:

(1)静态成员:

OutClass.InClass.f1();

(2)非静态成员:

//(1)创建静态内部类对象
OutClass.InClass inner = new OutClass.InClass();
//(2)通过对象调用非静态成员
inner.f2();
非静态内部类
class OutClass {
	public InClass getInClass() {
		return new InClass();
	}
	class InClass {
		void f() {}
	} 
}
  1. 不能有静态成员
  2. 外部类的静态成员不能直接访问非静态内部类
  3. 在外部类的外面访问非静态内部类的成员:
//(1)创建外部类对象
OutClass outer = new OutClass();
//(2)通过外部类对象创建或获取非静态内部类对象
//创建
OutClass.InClass inner_1 = outer.new InClass();
//获取
OutClass.InClass inner_2 = outer.getInClass();
//(3)通过对象调用成员
inner.f();

局部内部类

class OutClass {
	void f() {
		class InClass {
			//...
		}
	}
}
  1. 不能有静态成员
  2. 不能用权限修饰符和static修饰符
  3. 作用域为所在方法内
  4. 只能访问所在方法中的final变量
  5. 如果所在方法为静态方法,则不能直接访问外部类的非静态成员

匿名内部类

  1. 继承父类
abstract class Parent {
	public abstract void test();
}

class Test {
	public static void main(String[] args) {
		//父类引用指向匿名内部类对象
		Parent p = new Parent() {
			public void test() {
				System.out.println("匿名内部类继承Parent类");
			}
		};
		p.test();
	}
}
  1. 实现接口
interface Flyable {
	void fly();
}

class Test {
	public static void main(String[] args) {
		//接口引用指向匿名内部类对象
		Flyable f = new Flyable() {
			public void fly() {
				System.out.println("匿名内部类实现Flyable接口");
			}
		}; 
		f.fly();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值