【Java 面向对象,如何保证消息队列的高可用

	System.out.println("Person constructor");

} 

public class Student extends Person {

	static {

		System.out.println("Student static block");

	}

	{

		System.out.println("Student block");

	}

	public Student() {

		System.out.println("Student constructor");

	}

} 

```



**执行顺序**:父类静态块 -> 子类静态块 -> 父类代码块 -> 父类构造器 -> 子类代码块 -> 子类构造器



```

public static void main(String[] args) {

	new Student();

	// Person static block

	// Student static block

	// Person block

	// Person constructor

	// Student block

	// Student constructor

} 

```



[](https://gitee.com/vip204888/java-p7)单例模式(Singleton Pattern)

==========================================================================================



如果一个类设计成单例模式,那么在程序运行过程中,这个类只能创建一个实例。



**饿汉式单例模式**:像饿汉一样,上来就直接创建了唯一的那个实例。(线程安全)



```

/*

 * 饿汉式单例模式

 */

public class Rocket {

	private static Rocket instance = new Rocket();

	private Rocket(){}

	public static Rocket getInstance() {

		return instance;

	}

} 

```



**懒汉式单例模式**:像懒汉一样,只有用到的时候采取创建实例。(线程不安全)



```

/*

 * 懒汉式单例模式

 */

public class Rocket {

	private static Rocket instance = null;

	private Rocket(){}

	public static Rocket getInstance() {

		if (instance == null) {

			instance =  new Rocket();

		} 

		return instance;

	}

} 

```



[](https://gitee.com/vip204888/java-p7)final、常量(Constant)

=====================================================================================



被 `final` 修饰的类:**不能被子类化,不能被继承**



被 `final` 修饰的方法:**不能被重写**



被 `final` 修饰的变量:**只能进行1次赋值**



常量的写法:



*   `public static final double PI = 3.14159265358979323846;`

*   `private static final int NOT_FOUND = - 1;`



如果将**基本类型**或**字符串定义为常量**,并且**在编译时就能确定值**:



*   **编译器会使用常量值替代各处的常量名**(类似于 C 语言的宏替换)

*   称为**编译时常量**( compile-time constant)



例如下面的情况,**编译时会被替换**:



```

public class Main {

	static final int A = 123456;

	static final String B = "HELLO";

	public static void main(String[] args) {

		System.out.println(A); // 编译时直接被替换为下面

		// System.out.println(123456);

		

		System.out.println(B); // 编译时直接被替换为下面

		// System.out.println("HELLO");

	}

} 

```



下面这种情况,**编译时无法确定值,不会被替换**:



```

public class Main {

	static int NUMBER = getNum();

	static int getNum() {

		int a = 10;

		int b = 20;

		return a + b * 2 + 6;

	}

	

	public static void main(String[] args) {

		System.out.println(NUMBER); // 不会被替换

	}

} 

```



[](https://gitee.com/vip204888/java-p7)嵌套类(Nested Class)

====================================================================================



*   **嵌套类**:定义在另一个类中的类;

*   在嵌套类外层的类,称为:**外部类**(Outer Class)

*   最外层的外部类,称为:**顶级类**(Top-level Class)



```

public class OuterClass { // 顶级类

	// 静态嵌套类

	static class StaticNestedClass {

		

	}

	// 非静态嵌套类(内部类)

	class InnerClass {

		

	}

} 

```



[](https://gitee.com/vip204888/java-p7)内部类(Inner Class)

-----------------------------------------------------------------------------------



**内部类**:没有被 `static` 修饰的嵌套类,**非静态嵌套类**



跟实例变量、实例方法一样,内部类与外部类的实例相关联:



*   必须先创建外部类实例,然后再用外部类实例创建内部类实例

*   内部类不能定义除**编译时常量**以外的任何 static 成员



**内部类与外部类**:



*   内部类可以直接访问外部类中的所有成员(即使是 `private`)

*   外部类可以直接访问内部类实例的成员变量、方法(即使是 `private`)



内部类示例:先有公司 `company` 才能有员工 `employee`,将 `employee` 设置为 `company` 的内部类,而 `company` 可以访问 `employee` 的实例的成员变量、方法(包括`private`),`employee` 可以访问 `company` 的所有成员(包括 `private`)。



```

public class Company {

	private String name;

	public Company(String name) {

		this.name = name;

	}

	public void fire(Employee e) {

		// 外部类可以直接访问内部类实例的成员变量(包括 private)

		System.out.println(name + " fire " + e.no);

	}

	

	

	public class Employee {

		private int no;

		public Employee(int no) {

			this.no = no;

		}

		public void show() {

			// 内部类可以直接访问外部类中的所有成员(包括 private)

			System.out.println(name + " : " + no);

		}

	}

	

	public static void main(String[] args) {

		Company c = new Company("Google");

		Employee e = c.new Employee(17210224);

		e.show();

		c.fire(e);

	}

} 

```



**内部类的细节**:如果有**同名变量**,默认访问内部的,访问外部的需要特别指出。



```

public class OuterClass {

	private int x = 1; // 外部类变量x

	public class InnerClass {

		private int x = 2; // 内部类变量x

		public void show() {

			// 默认访问内部

			System.out.println(x); // 2

			System.out.println(this.x); // 2

			// 访问外部类的同名变量需要这么写

			System.out.println(OuterClass.this.x); // 1

		}

	}



	public static void main(String[] args) {

		new OuterClass().new InnerClass().show();

	}

} 

```



### [](https://gitee.com/vip204888/java-p7)内部类内存分布



```

public class Person {

	private int age;

	

	public class Hand {

		private int weight;

	}

	

	public static void main(String[] args) {

		// 必须先有Person对象才能创建Hand对象

		Person p1 = new Person();

		Hand h1 = p1.new Hand();

		

		Person p2 = new Person();

		Hand h2 = p2.new Hand();

	}

} 

```



在 `Hand` 类被释放前,`Person` 类不会被释放(被 `Hand` 指向着)  

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200425081915382.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzczNDA5NQ==,size_16,color_FFFFFF,t_70)



[](https://gitee.com/vip204888/java-p7)静态嵌套类(Static Nested Class)

---------------------------------------------------------------------------------------------



**静态嵌套类**:被 `static` 修饰的**嵌套类**;



静态嵌套类在**行为上**就是一个顶级类,只是定义的代码写在了另一个类中;



对比一般的顶级类,静态嵌套类多了一些特殊权限



*   可以直接访问外部类中的成员(即使被声明为 `private`)



```

public class Person {

	private int age;

	private static int count = 1;

	private static void run() {

		System.out.println("Person - run");

	}

	

	public static class Car { // 静态嵌套类

		public void test() {

			Person person = new Person();

			// 静态嵌套类可以直接访问外部类中的成员(包括 private)

			System.out.println(person.age); // 0

			Person.count = 1;

			Person.run(); // Person - run

			

			System.out.println(count); // 1

			run(); // Person - run

		}

	}

} 

public static void main(String[] args) {

Person p = new Person();

// 静态嵌套类的使用

Person.Car c = new Person.Car(); 

// 如果之前 import Person.Car; 可以直接使用;

// Car c = new Car();

c.test();

}




[](https://gitee.com/vip204888/java-p7)什么情况使用嵌套类?

-----------------------------------------------------------------------------



如果类 A 只用在类 C 内部,可以考虑将类 A 嵌套到类 C 中;



*   封装性更好

*   程序包更加简化

*   增强可读性、维护性



如果类 A 需要经常访问类 C 的**非公共成员**,可以考虑将类 A嵌套到类 C 中;



*   另外也可以根据需要将类 A 隐藏起来,不对外暴露



如果需要**经常访问非公共的实例成员**,设计成内部类(非静态嵌套类),否则设计成静态嵌套类;



*   如果必须先有 C 实例,才能创建 A 实例,那么可以将 A 设计为 C 的内部类



[](https://gitee.com/vip204888/java-p7)局部类(Local Class)

===================================================================================



**局部类**:定义在**代码块**中的类(可以定义在方法中、for 循环中、if 语句中等)



局部类不能定义除**编译时常量**以外的任何 `static` 成员;



局部类只能访问 `final` 或者 **有效`final`** 的局部变量;



*   从 Java 8 开始,如果**局部变量没有被第二次赋值**,就认定为是**有效`final`**



局部类可以直接访问外部类中的所有成员(即使被声明为 `private`)



*   局部类只有定义在实例相关的代码块中,才能直接访问外部类中的实例成员(实例变量、实例方法)



局部类示例:



public class TestLocalClass {

private int a = 1;

private static int b = 2;

private static void test1() {}

private void test2() {}



public void test3() {

	int c = 2;

	

	class LocalClass {

		static final int d = 4;

		void test4() {

			System.out.println(a + b + c  + d);

			test1();

			test2();

		}

	}

	new LocalClass().test4();

}

}




[](https://gitee.com/vip204888/java-p7)抽象类(Abstract Class)与接口(Interface)

====================================================================================================



[](https://gitee.com/vip204888/java-p7)抽象类

----------------------------------------------------------------------



**抽象方法**:被 `abstract` 修饰的实例方法



*   只有方法声明,没有方法实现(参数列表后面没有大括号,而是分号)

*   不能是 `private` 权限(因为定义抽象方法的目的让子类去实现)

*   只能定义在抽象类、接口中



**抽象类**:被 `abstract` 修饰的类



*   可以定义抽象方法

*   不能实例化,但可以自定义构造方法

*   子类必须实现抽象父类中的所有抽象方法(除非子类也是一个抽象类)

*   可以像非抽象类一样定义成员变量、常量、嵌套类型、初始化块、非抽象方法等  

    也就说,**抽象类也可以完全不定义抽象方法**



常见使用场景:



*   抽取子类的公共实现到抽象父类中,要求子类必须要单独实现的定义成抽象方法



实例:



public abstract class Shape {

protected double area;

protected double girth;

public double getArea() {

	return area;

}

public double getGirth() {

	return girth;

}

public void show() {

	calculate();

	System.out.println(area + "_" + girth);

}

protected abstract void calculate();

}


public class Rectangle extends Shape {

	private double width;

	private double height;

	public Rectangle(double width, double height) {

		super();

		this.width = width;

		this.height = height;

	}

	@Override

	protected void calculate() {

		area = width * height;

		girth = (width + height) * 2;

	}

} 

public class Circle extends Shape {

private double radius;

public Circle(double radius) {

	this.radius = radius;

}

@Override

protected void calculate() {

	double half = Math.PI * radius;

	area = half * radius;

	girth = half * 2;

}

}


public static void main(String[] args) {

	Rectangle rectangle = new Rectangle(10, 20);

	rectangle.show();

	

	Circle circle = new Circle(30);

	circle.show();

} 

```



[](https://gitee.com/vip204888/java-p7)接口(Interface)

--------------------------------------------------------------------------------



**API**(Application Programming Interface)



*   **应用编程接口**,提供给开发者调用的一组功能(无须提供源码)



**Java 中的接口**:



*   一系列方法声明的集合

*   用来定义规范、标准



**接口中可以定义的内容**:



*   **抽象方法(可以省略 abstract)**

*   **常量(可以省略 static、final)**

*   **嵌套类型**

*   从 Java 8 开始可以定义:**默认方法(`default`)**、**静态方法**  

    上述可以定义的内容都是隐式 public 的,因此可以省略 public 关键字

*   从 Java 9 开始可以定义:**private 方法**

*   不能自定义构造方法、不能定义(静态)初始化块、不能实例化



**接口的细节**:  

一个类可以通过 `implements` 关键字实现一个或多个接口



*   实现接口的类必须实现接口中定义的所有抽象方法,除非它是个抽象类

*   如果一个类实现的多个接口中有相同的抽象方法,只需要实现此方法一次

*   `extends` 和 i`mplements` 可以一起使用,`implements` 必须写在 `extends` 的后面

*   当父类、接口中的方法签名一样时,那么返回值类型也必须一样



一个接口可以通过 `extends` 关键字继承一个或者多个接口



*   当多个父接口中的方法签名一样时,那么返回值类型也必须一样



[](https://gitee.com/vip204888/java-p7)抽象与接口的对比(如何选择)

---------------------------------------------------------------------------------



抽象类和接口的用途还是有点类似,该如何选择?



何时选择**抽象类**?



*   在**紧密相关的类**之间共享代码

*   需要除 public 之外的访问权限

*   需要定义实例变量、非 final 的静态变量



何时选择**接口**?



*   **不相关的类**实现相同的方法

*   只是**定义行为**,不关心具体是谁实现了行为

*   想实现类型的**多重继承**



[](https://gitee.com/vip204888/java-p7)接口的升级问题(默认方法、静态方法)

=====================================================================================



如果接口需要升级,比如增加新的抽象方法:会导致大幅的代码改动,以前实现接口的类都得改动



若想在不改动以前实现类的前提下进行接口升级,从 Java 8 开始,有 2 种方案:



*   **默认方法**(Default Method)

*   **静态方法**(Static Method)



[](https://gitee.com/vip204888/java-p7)默认方法(Default Method)

---------------------------------------------------------------------------------------



*   用 `default` 修饰默认方法

*   默认方法只能是实例方法



**默认方法的使用**:  

当一个类实现的接口中有默认方法时,这个类可以:



*   **啥也不干**,沿用接口的默认实现

*   重新定义默认方法,**覆盖**默认方法的实现

*   重新声明默认方法,将默认方法声明为抽象方法(此类必须是抽象类)



当一个接口继承的父接口中有默认方法时,这个接口可以:



*   **啥也不干**,沿用接口的默认实现

*   重新定义默认方法,**覆盖**默认方法的实现

*   重新声明默认方法,将默认方法声明为抽象方法



简单示例:`Eatable` 中有默认方法,`Dog`啥也不干,`Cat` 覆盖默认方法。



```

public interface Eatable {

	// 默认方法

	default void eat(String name) {

		System.out.println("Eatable - eat - " + name);

	}

} 

// Eatable接口中新增了方法, 但是没有影响到Dog类

public class Dog implements Eatable {}


// Eatable接口中新增了方法, Cat类中可以覆盖

public class Cat implements Eatable {

	@Override

	public void eat(String name) {

		Eatable.super.eat(name);

		System.out.println("Cat - eat - " + name);

	}

} 

public static void main(String[] args) {

	Dog dog = new Dog();

	dog.eat("bone"); 

	// Eatable - eat - bone

	

	Cat cat = new Cat();

	cat.eat("fish");

	// Eatable - eat - fish

	// Cat - eat - fish

} 



如果父类定义的非抽象方法与接口的默认方法相同时,最终将调用父类的方法(**就近原则**):



public class Animal {

public void run() {

	System.out.println("Animal - run");

}

}


public interface Runnable {

	default void run() {

		System.out.println("Runnable - run");

	}

} 

public class Dog extends Animal implements Runnable {}


public static void main(String[] args) {

	Dog dog = new Dog();

	dog.run(); // 继承的父类、实现的接口中都有 run() 方法, 默认调用父类的

	// Animal - run

} 

```



如果父类定义的抽象方法与接口的默认方法相同时,要求子类实现此抽象方法



*   可以通过 `super` 关键字调用接口的默认方法



```

public interface Runnable {

	default void run() {

		System.out.println("Runnable - run");

	}

} 

public abstract class Animal {

public void run() {}

}


public class Dog extends Animal implements Runnable {

	@Override

	public void run() { // 父类的抽象方法run方法与接口中的run方法相同, 要求实现父类的抽象方法

		Runnable.super.run(); // 可以通过super调用接口的默认方法

		System.out.println("Dog - run");

		// Runnable - run

		// Dog - run

	}

} 

```



如果(父)接口定义的默认方法与其他(父)接口定义的方法相同时,要求子类型实现此默认方法:  

例:`Runnable` 和 `Walkable` 两个父接口中定义的**默认方法**都是 `run()`,`Testable` 继承了两个父类,则要求实现默认方法 `run()` ,`Dog` 类同理。



```

public interface Runnable {

	default void run() {

		System.out.println("Runnable - run");

	}

} 

public interface Walkable {

default void run() {

	System.out.println("Walkable - run");

}

}


// Testable 父接口继承了 Runnable 父接口和 Walkable 父接口

// 他们都有默认方法 run, 要求 Testable 接口实现该默认方法

public interface Testable extends Runnable, Walkable {

	@Override

	default void run() {

		Runnable.super.run();

		Walkable.super.run();

		System.out.println("Testable - run");

	}

} 

// Dog 类实现了 Runnable、Walkable 两个接口

// 他们都有默认方法 run, 要求 Dog 类实现该默认方法

public class Dog implements Runnable, Walkable {

@Override

public void run() {

	Runnable.super.run();

	Walkable.super.run();

	System.out.println("Dog - run");

}

}


public static void main(String[] args) {

	Dog dog = new Dog();

	dog.run();

	// Runnable - run

	// Walkable - run

	// Dog - run

} 

```



再看一个例子:



```

public interface Animal {

	default String myself() {

		return "I am an animal.";

	}

} 

public interface Fire extends Animal {}


public interface Fly extends Animal {

	@Override

	default String myself() {

		return "I am able to fly.";

	}

} 

public class Dragon implements Fly, Fire {}


public static void main(String[] args) {

	Dragon dragon = new Dragon();

	System.out.println(dragon.myself());

	// I am able to fly.

} 

```



[](https://gitee.com/vip204888/java-p7)静态方法(Static Method)

--------------------------------------------------------------------------------------



*   接口中定义的静态方法只能通过接口名调用,**不能被继承**;



```

public interface Eatable {

	static void eat(String name) {

		System.out.println("Eatable - eat - " + name);

	}

} 

public interface Sleepable {

static void eat(String name) {

	System.out.println("Sleepable - eat - " + name);

}

}


public interface Dog extends Sleepable, Eatable {

	static void eat(String name) {

		System.out.println("Dog - eat - " + name);

	}

} 

public static void main(String[] args) {

Dog.eat("1");

Eatable.eat("1");

Sleepable.eat("3");

// Dog - eat - 1

// Eatable - eat - 1

// Sleepable - eat - 3

}




[](https://gitee.com/vip204888/java-p7)多态(Polymorphism)

===================================================================================



什么是多态?



*   具有多种形态

*   同一操作作用于不同的对象,产生不同的执行结果



多态的体现:



*   **父类(接口)类型指向子类对象**

*   **调用子类重写的方法**



JVM 会根据引用变量指向的具体对象来调用对应的方法:



*   这个行为叫做:虚方法调用(virtual method invocation)

*   类似于 C++ 中的虚函数调用



多态示例:



public class Animal {

public void speak() {

	System.out.println("Animal - speak");

}

}


public class Dog extends Animal {

	@Override

	public void speak() {

		System.out.println("Dog - wangwang");

	}

} 

public class Cat extends Animal {

@Override

public void speak() {

	System.out.println("Cat - miaomiao");

}

}


public static void main(String[] args) {

	speak(new Dog()); // Dog - wangwang

	speak(new Cat()); // Cat - miaomiao

}

// 多态的体现: 父类(接口)类型指向子类对象, 调用子类重写的方法

static void speak(Animal animal) {

	animal.speak();

} 

```



# 总结

谈到面试,其实说白了就是刷题刷题刷题,天天作死的刷。。。。。

为了准备这个“金三银四”的春招,狂刷一个月的题,狂补超多的漏洞知识,像这次美团面试问的算法、数据库、Redis、设计模式等这些题目都是我刷到过的

**并且我也将自己刷的题全部整理成了PDF或者Word文档(含详细答案解析),[有需要的朋友可以戳这里即可免费领取](https://gitee.com/vip204888/java-p7)**

![我的美团offer凉凉了?开发工程师(Java岗)三面结束等通知...](https://img-blog.csdnimg.cn/img_convert/770d2ba0dacfa221245720f94143747b.png)

66个Java面试知识点

**架构专题(MySQL,Java,Redis,线程,并发,设计模式,Nginx,Linux,框架,微服务等)+大厂面试题详解(百度,阿里,腾讯,华为,迅雷,网易,中兴,北京中软等)**

![我的美团offer凉凉了?开发工程师(Java岗)三面结束等通知...](https://img-blog.csdnimg.cn/img_convert/4b2512d8637836fb6581d4c9134d0acc.png)

**算法刷题(PDF)**


```



[](https://gitee.com/vip204888/java-p7)多态(Polymorphism)

===================================================================================



什么是多态?



*   具有多种形态

*   同一操作作用于不同的对象,产生不同的执行结果



多态的体现:



*   **父类(接口)类型指向子类对象**

*   **调用子类重写的方法**



JVM 会根据引用变量指向的具体对象来调用对应的方法:



*   这个行为叫做:虚方法调用(virtual method invocation)

*   类似于 C++ 中的虚函数调用



多态示例:



```

public class Animal {

	public void speak() {

		System.out.println("Animal - speak");

	}

} 

public class Dog extends Animal {

@Override

public void speak() {

	System.out.println("Dog - wangwang");

}

}


public class Cat extends Animal {

	@Override

	public void speak() {

		System.out.println("Cat - miaomiao");

	}

} 

public static void main(String[] args) {

speak(new Dog()); // Dog - wangwang

speak(new Cat()); // Cat - miaomiao

}

// 多态的体现: 父类(接口)类型指向子类对象, 调用子类重写的方法

static void speak(Animal animal) {

animal.speak();

}




# 总结

谈到面试,其实说白了就是刷题刷题刷题,天天作死的刷。。。。。

为了准备这个“金三银四”的春招,狂刷一个月的题,狂补超多的漏洞知识,像这次美团面试问的算法、数据库、Redis、设计模式等这些题目都是我刷到过的

**并且我也将自己刷的题全部整理成了PDF或者Word文档(含详细答案解析),[有需要的朋友可以戳这里即可免费领取](https://gitee.com/vip204888/java-p7)**

[外链图片转存中...(img-QSnG07b9-1628506140106)]

66个Java面试知识点

**架构专题(MySQL,Java,Redis,线程,并发,设计模式,Nginx,Linux,框架,微服务等)+大厂面试题详解(百度,阿里,腾讯,华为,迅雷,网易,中兴,北京中软等)**

[外链图片转存中...(img-ceKJaSuI-1628506140108)]

**算法刷题(PDF)**

![我的美团offer凉凉了?开发工程师(Java岗)三面结束等通知...](https://img-blog.csdnimg.cn/img_convert/2ba1bf4a59eb3579867ebfb6dafbdc0c.png)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值