Java进阶
面向对象高级
static
1、static是什么
static 是 静态 可以用于修饰 变量,方法,代码块,内部类。
注意:是内部类:在一个类中声明的类,static无法修饰最外层的类。
public class OuterClass {
int a=0;
private int b=0;
// 静态嵌套类
public static class StaticNestedClass {
// 静态嵌套类的成员
public void display(OuterClass o) {
System.out.println("Inside StaticNestedClass"+o.b);
System.out.println("Inside StaticNestedClass"+o.a);
}
}
public static void main(String[] args) {
// 通过外部类来创建静态嵌套类的实例
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
nestedObject.display(new OuterClass());
//单独创建静态嵌套类的实例
StaticNestedClass nestedObject2 = new StaticNestedClass();
nestedObject2.display(new OuterClass());
}
}
静态嵌套类有以下几个特点:
-
它们是独立于外部类实例的,这意味着你可以不创建外部类的实例而直接创建静态嵌套类的实例。
-
静态嵌套类可以通过外部类的实例直接访问外部类的所有成员,包括私有的成员。
-
创建静态嵌套类的对象不会影响外部类的状态。
不会影响外部类的状态:
- 实例变量:静态嵌套类的实例化和使用不会改变外部类的实例变量的值。
- 方法执行:静态嵌套类的实例化和使用不会影响外部类的方法的执行结果。
2、static修饰的成员变量叫什么? 怎么使用?有啥特点 ?
public class StaticClass {
static int a;
static int b;
public static void main(String[] args) {
System.out.println(StaticClass.a);
System.out.println(StaticClass.b);
//特点会被类的所有变量共享
a=10;
StaticClass staticClass1=new StaticClass();
StaticClass staticClass2=new StaticClass();
StaticClass staticClass3=new StaticClass();
System.out.println("对象1:"+staticClass1.a);//10
System.out.println("对象2:"+staticClass2.a);//10
System.out.println("对象3:"+staticClass3.a);
//改变其中一个对象a的值其他对象的a都会改变
staticClass1.a=20;
//
System.out.println("--------改变后---------");
System.out.println("对象:1"+staticClass1.a);//20
System.out.println("对象:2"+staticClass2.a);//20
System.out.println("对象:3"+staticClass3.a);//20
}
}
对象1:10
对象2:10
对象3:10
--------改变后---------
对象1:20
对象2:20
对象3:20
- static修饰的成员变量叫类变量(静态成员变量)
- 使用类名.变量名称使用StaticClass.a
- 特点:属于类,与类一起加载一次,在内存中只有一份,会被类的所有对象共享
3、static注意事项
- 类方法中可以直接访问类的成员,不可以直接访问实例成员。
- 实例方法中既可以直接访问类成员,也可以直接访问实例成员。
- 实例方法中可以出现this关键字,类方法中不可以出现this关键字的。
面向对象三大特征
一、封装
定义
封装是指将数据(属性)和操作数据的方法绑定在一起作为一个单独的单元(即类),并且尽可能隐藏类的内部实现细节,只暴露对外接口给外部使用。
目的
- 数据保护:防止外部直接访问或修改对象的内部状态,提高安全性。
- 代码复用性:通过提供公共方法来操作私有数据成员,使得代码更加模块化,易于重用。
- 维护简便:当需要改变类的内部实现时,只要不改变其对外提供的接口,就不会影响到其他部分的代码。
实现方式
-
访问修饰符:Java提供了四种不同的访问级别,分别是
public
、protected
、private
和默认(无关键字)。通常将类中的字段设置为private
,以防止外部直接访问。 -
getter和setter方法:为了允许外部安全地读取或修改私有字段,可以通过提供公共的getter(获取器)和setter(设置器)方法来间接访问这些字段。
-
final关键字:可以使用
final
关键字来阻止类的继承或者方法的覆盖,从而保护类或方法不被更改。 -
内部类:在某些情况下,可以使用内部类来封装数据和行为,这样只有包含该内部类的外部类才能访问它。
public class Person { // 私有字段 private String name; private int age; // 默认构造函数 public Person() {} // 带参数的构造函数 public Person(String name, int age) { this.name = name; this.age = age; } // Getter for name public String getName() { return name; } // Setter for name public void setName(String name) { this.name = name; } // Getter for age public int getAge() { return age; } // Setter for age public void setAge(int age) { if (age > 0) { // 添加简单的验证逻辑 this.age = age; } else { System.out.println("年龄必须大于0"); } } }
二、继承
定义
继承是面向对象编程中一个重要的概念,它允许一个类(子类或派生类)继承另一个类(父类或基类)的属性和方法。通过继承,子类可以获得父类的所有非私有成员(字段和方法),并且可以添加新的方法和字段,或者重写父类的方法以实现多态性。
目的
- 代码复用:子类可以直接使用父类已经定义好的属性和方法,避免重复编写相同的代码。
- 层次结构:通过继承可以建立类之间的层次关系,使得类的设计更加清晰和合理。
- 扩展性:子类可以在不修改父类的情况下增加新的功能,提高了代码的灵活性和可扩展性。
实现方式
extends
:用于声明一个类继承自另一个类。例如:
public class B{
}
public class A extends B {
// 子类的定义
}
访问控制
访问修饰符 | 本类 | 同一个包中的类 | 子孙类 | 任意类 |
---|---|---|---|---|
public | √ | √ | √ | √ |
privte | √ | |||
默认(没有填写访问修饰符) | √ | √ | ||
protected | √ | √ | √ |
方法重写
- 子类可以重写父类的方法以提供特定的实现。
- 使用
@Override
注解可以明确表示这是一个重写方法,有助于编译器检查错误。 - 重写方法的访问权限不能比父类的方法更严格。
子类访问其他成员的特点
就近原则
- 先子类局部范围找。
- 然后子类成员范围找。
- 然后父类成员范围找,如果父类范围还没有找到则报错。
子父类出现了重名的成员,会优先使用子类的,想要使用父类的
可以通过super关键字,指定访问父类的成员:super.父类成员变量/父类成员方法
子类构造器的特点
- 子类的全部构造器,都会先调用父类的构造器,再执行自己使用super(…)调用,默认存在。
- 如果父类没有无参数构造器,则我们必须在子类构造器的第一行手写super(….),指定去调用父类的有参数构造器。
- this(…)和super(…)使用时的注意事项:this(…) 、super(…) 都只能放在构造器的第一行,两者不能共存。
示例
// 父类 Animal
public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(name + " is eating.");
}
public void sleep() {
System.out.println(name + " is sleeping.");
}
}
// 子类 Dog
public class Dog extends Animal {
public Dog(){
this("哈哈")
}
public Dog(String name) {
super(name); // 调用父类的构造器
}
@Override
public void eat() {
System.out.println(name + " is eating dog food.");
}
public void bark() {
System.out.println(name + " is barking.");
}
}
// 测试类
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog("Buddy");
myDog.eat(); // 输出: Buddy is eating dog food.
myDog.sleep(); // 输出: Buddy is sleeping.
myDog.bark(); // 输出: Buddy is barking.
}
}
多次继承
- Java 不支持多重继承(一个类不能继承多个类),但可以通过接口实现类似的功能。
注意事项
- 过度继承:过多的继承层次可能导致代码复杂性和维护难度增加。
- 继承与组合:在某些情况下,使用组合(Composition)而不是继承可能更合适。组合是指在一个类中包含另一个类的对象,而不是继承它的行为。
三、多态
定义
多态是指同一个接口或引用类型可以表示不同的实际类型的能力。多态使得子类对象可以被当作父类对象来使用,从而增加了代码的灵活性和可扩展性。Java中的多态主要通过方法重写(Method Overriding)和接口实现(Interface Implementation)来实现。
目的
- 代码复用:通过多态,可以使用统一的接口来处理不同类型的对象,减少了代码的冗余。
- 灵活性:多态使得程序可以在运行时决定具体的行为,增强了代码的动态性。
- 扩展性:新增加的子类可以很容易地集成到现有的系统中,而不需要修改已有的代码。
类型
编译时多态(静态多态):通过方法重载(Method Overloading)实现。
方法重载
- 方法重载是指在同一个类中,可以有多个同名但参数列表不同的方法。
- 编译器根据传入参数的不同来决定调用哪个方法。
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
}
运行时多态(动态多态):通过方法重写(Method Overriding)和接口实现(Interface Implementation)实现。
方法重写
- 方法重写是指子类重新定义父类中已经存在的方法。
- 使用
@Override
注解可以明确表示这是一个重写方法,有助于编译器检查错误。 - 重写方法的访问权限不能比父类的方法更严格。
public class Animal {
public void makeSound() {
System.out.println("Some generic sound");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Bark");
}
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow");
}
}
接口实现 (Interface Implementation)
- 接口定义了一组方法,但没有具体的实现。
- 类可以通过实现接口来提供这些方法的具体实现。
- 实现接口也可以实现多态。
public interface Animal {
void makeSound();
}
public class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Bark");
}
}
public class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("Meow");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
Animal myCat = new Cat();
myDog.makeSound(); // 输出: Bark
myCat.makeSound(); // 输出: Meow
}
}
注意事项
- 向上转型:将子类对象赋值给父类引用的过程称为向上转型,这是隐式的,不需要强制转换。
- 向下转型:将父类引用转换为子类对象的过程称为向下转型,这是显式的,需要强制转换,并且需要确保引用的实际对象是子类的实例,否则会抛出
ClassCastException
异常。
final关键字
定义
final
是一个修饰符,可以应用于类、方法和变量,具有不同的作用和用途。
final修饰变量
- 定义:
final
修饰的变量是一个常量,一旦被赋值就不能再被改变。 - 用途:用于定义常量,确保数据的不可变性,提高代码的安全性和可读性。
public class Constants {
public final int MAX_VALUE = 100;
public Constants() {
// 试图改变final变量的值会导致编译错误
// MAX_VALUE = 200; // 编译错误
}
public static void main(String[] args) {
Constants c = new Constants();
// 试图改变final变量的值会导致编译错误
// c.MAX_VALUE = 200; // 编译错误
System.out.println(c.MAX_VALUE); // 输出: 100
}
}
final修饰方法
- 定义:
final
修饰的方法不能被子类重写。 - 用途:防止子类改变父类的方法实现,确保某些方法的行为在所有子类中保持一致。
public class BaseClass {
public final void display() {
System.out.println("This is a final method.");
}
}
public class DerivedClass extends BaseClass {
// 试图重写final方法会导致编译错误
// @Override
// public void display() {
// System.out.println("Trying to override final method.");
// }
}
public class Main {
public static void main(String[] args) {
DerivedClass obj = new DerivedClass();
obj.display(); // 输出: This is a final method.
}
}
final 修饰类
- 定义:
final
修饰的类不能被继承。 - 用途:防止类被子类化,确保类的完整性和安全性,适用于那些不应该被扩展的类。
public final class FinalClass {
public void display() {
System.out.println("This is a final class.");
}
}
// 试图继承final类会导致编译错误
// public class DerivedClass extends FinalClass {
// }
public class Main {
public static void main(String[] args) {
FinalClass obj = new FinalClass();
obj.display(); // 输出: This is a final class.
}
}
final参数
- 定义:
final
修饰的参数在方法体内不能被修改。 - 用途:确保方法体内的参数值不会被改变,提高代码的安全性和可读性。
public class FinalParameterExample {
public void display(final String message) {
// 试图修改final参数会导致编译错误
// message = "New message"; // 编译错误
System.out.println(message);
}
public static void main(String[] args) {
FinalParameterExample example = new FinalParameterExample();
example.display("Hello, World!"); // 输出: Hello, World!
}
}
final 对象的不可变性
- 定义:如果一个对象被声明为
final
,那么这个对象的引用不能被改变,但对象内部的状态仍然可以改变。 - 用途:确保对象引用的不变性,但需要注意对象内部的状态是否也应该是不可变的。
public class FinalObjectExample {
public final StringBuilder sb = new StringBuilder("Initial");
public void changeStringBuilder() {
// 试图改变final对象的引用会导致编译错误
// sb = new StringBuilder("New"); // 编译错误
// 但可以改变对象内部的状态
sb.append(" Changed");
}
public static void main(String[] args) {
FinalObjectExample example = new FinalObjectExample();
example.changeStringBuilder();
System.out.println(example.sb.toString()); // 输出: Initial Changed
}
}
抽象类
定义
- 抽象类:使用
abstract
关键字修饰的类。 - 抽象方法:使用
abstract
关键字修饰的方法,没有具体实现(即没有方法体)。
特点
- 不能实例化:抽象类不能直接创建对象,只能被继承。
- 包含抽象方法:抽象类可以包含抽象方法,子类必须实现这些抽象方法。
- 包含具体方法:抽象类可以包含具体方法,子类可以直接继承这些方法。
- 构造器:抽象类可以有构造器,主要用于初始化子类对象。
- 普通成员变量:抽象类可以包含普通成员变量。
用途
- 提供模板:定义一个类的框架,规定子类必须实现的某些方法。
- 代码复用:提供一些通用的方法实现,供子类继承和使用。
- 多态:通过抽象类实现多态,增强代码的灵活性和扩展性。
示例
假设我们有一个抽象类Animal
,它定义了一个抽象方法makeSound
,以及一个具体方法eat
。然后我们定义两个子类Dog
和Cat
,它们分别实现了makeSound
方法。
// 抽象类 Animal
public abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
// 抽象方法
public abstract void makeSound();
// 具体方法
public void eat() {
System.out.println(name + " is eating.");
}
}
// 子类 Dog
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println(name + " says: Bark");
}
}
// 子类 Cat
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println(name + " says: Meow");
}
}
// 测试类
public class Main {
public static void main(String[] args) {
// 不能创建抽象类的实例
// Animal animal = new Animal("Generic Animal"); // 编译错误
Animal myDog = new Dog("Buddy");
Animal myCat = new Cat("Whiskers");
myDog.makeSound(); // 输出: Buddy says: Bark
myDog.eat(); // 输出: Buddy is eating.
myCat.makeSound(); // 输出: Whiskers says: Meow
myCat.eat(); // 输出: Whiskers is eating.
}
}
详细解释
- 抽象类
Animal
:- 包含一个受保护的成员变量
name
。 - 包含一个构造器,用于初始化
name
。 - 包含一个抽象方法
makeSound
,子类必须实现这个方法。 - 包含一个具体方法
eat
,子类可以直接继承这个方法。
- 包含一个受保护的成员变量
- 子类
Dog
和Cat
:- 都继承了抽象类
Animal
。 - 都实现了抽象方法
makeSound
,提供了具体的实现。 - 都可以调用继承自
Animal
的具体方法eat
。
- 都继承了抽象类
注意事项
- 抽象类不能实例化:不能直接创建抽象类的实例,只能通过子类来实例化。
- 抽象方法必须被实现:子类必须实现抽象类中的所有抽象方法,除非子类也是抽象类。
- 抽象类可以包含具体方法:抽象类不仅可以包含抽象方法,还可以包含具体方法和成员变量。
接口
未完待续