目录
1、面向对象概述:
类(Class):类是定义对象的模板或蓝图。它描述了对象的属性(字段)和行为(方法)。
对象(Object):对象是类的一个实例。每个对象都具有类定义的属性和行为。
封装(Encapsulation):封装是一种将数据和方法结合在一个单元中的机制。通过封装,类可以隐藏其内部实现细节,并提供对外访问的接口。
继承(Inheritance):继承是一种对象之间的关系,其中一个类(称为子类)可以从另一个类(称为父类)继承属性和行为。继承可以实现代码重用和层级结构的创建。
多态(Polymorphism):多态是指一个对象可以具有多种形态。它允许使用基类类型的变量来引用子类对象,并根据实际对象的类型来调用相应的方法。
方法(Method):方法是类中定义的操作或行为。它们用于执行特定的任务。
成员变量(Member Variables):成员变量是类中定义的变量,用于存储对象的状态。它们也被称为实例变量,因为每个对象都有自己的一组成员变量。
构造函数(Constructor):构造函数是用于创建对象的特殊方法。它们与类具有相同的名称,并在实例化对象时被调用。
2、面向对象和面向过程的区别
设计理念:面向对象编程(OOP)的设计理念是将问题分解为对象的集合,并定义对象之间的相互关系。面向过程编程(Procedural Programming)则是将问题分解为一系列的步骤和操作。
数据和行为封装:在面向对象编程中,数据和相应的行为封装在对象中,形成了类的实例。这种封装提供了更好的抽象和封装性,并允许隐藏实现细节。在面向过程编程中,数据和行为是分离的,函数或过程对数据进行处理和操作。
继承和多态:面向对象编程允许使用继承来创建类层次结构,并通过多态来实现多种形态的行为。这种特性提供了代码重用和灵活性。面向过程编程通常没有继承和多态的概念,因为重点是过程和顺序的流程。
强调对象和类:在面向对象编程中,强调对象和类的概念。类是对象的模板,用于描述对象的属性和行为。对象是类的实例,具有独立的状态和行为。在面向过程编程中,更强调函数或过程的概念,数据和函数是分离的。
可维护性和扩展性:面向对象编程通常提供更好的可维护性和扩展性。由于封装、继承和多态的特性,代码更易于理解、测试和修改。面向过程编程可能会导致代码的重复和依赖,降低可维护性和扩展性。
3、类与对象
类(Class):
- 类是一个代码模板,用于创建具有相似特征和行为的对象。
- 它是对象的蓝图,描述了对象中的属性和方法。
- 类通常定义在一个.java文件中,具有成员变量和方法。
对象(Object):
- 对象是类的一个实例。通过实例化一个类,我们可以创建一个对象。
- 对象具有类定义的属性和行为。每个对象都是独立的,它们有自己的状态(通过类的成员变量表示)和行为(通过类的方法表示)。
- 对象可以用于执行操作,访问类的成员变量,并调用类的方法。
类与对象之间的关系:
- 类是对象的模板,它定义了对象的属性和行为。它是对象的抽象描述。
- 对象是由类创建的实体,它具有类中定义的属性和方法。
- 可以通过使用
new
关键字和类的构造函数来创建一个对象:ClassName objectName = new ClassName();
-
public class People{ String name="张三"; String sex="男"; int age=18; public static void main(String[] args){ People p=new People(); System.out.printf("%s %s %d\n",p.name,p.age,p.age); } }
通过对象的引用变量可以访问对象的属性和调用对象的方法。
// 类的定义
public class Person {
// 成员变量
String name;
int age;
// 构造函数
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 方法
public void sayHello() {
System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
}
}
// 创建对象并访问属性和调用方法
public class Main {
public static void main(String[] args) {
// 创建Person对象
Person person = new Person("John", 25);
// 访问属性
System.out.println(person.name); // 输出:John
System.out.println(person.age); // 输出:25
// 调用方法
person.sayHello(); // 输出:Hello, my name is John and I am 25 years old.
}
}
通过类和对象的使用,Java提供了一种面向对象的编程方式,使得程序能够更好地建模和处理问题。
4、this关键字
引用当前对象:
this
关键字用于引用当前对象,它指向正在执行方法或构造函数的对象实例。它允许在当前对象的作用域内引用对象的成员变量、方法和构造函数。避免命名冲突:当实例变量与方法参数或局部变量同名时,可以使用
this
关键字来区分。通过使用this
关键字,编译器可以区分当前对象的成员变量和其他变量。在构造函数中调用其他构造函数:在构造函数中,可以使用
this
关键字调用同一类的其他构造函数。这种方式称为构造函数的重载。通过重载构造函数,可以在创建对象时提供不同的参数组合。传递当前对象作为参数:可以使用
this
关键字将当前对象作为参数传递给其他方法或构造函数。这样可以将当前对象的引用传递到其他方法或构造函数中,以便进行进一步处理。
public class Person {
private String name;
public Person(String name) {
this.name = name; // 使用 this 关键字引用当前对象的成员变量
}
public void printName() {
System.out.println("My name is " + this.name); // 使用 this 关键字引用当前对象的方法和成员变量
}
public void setName(String name) {
this.name = name; // 使用 this 关键字引用当前对象的成员变量和方法参数
}
public Person() {
this("John"); // 使用 this 关键字调用同一类的其他构造函数
}
public void doSomething() {
OtherClass.process(this); // 将当前对象作为参数传递给其他方法
}
}
this
关键字在Java中具有重要的作用,它允许在当前对象的上下文中引用成员变量、方法和构造函数,提供灵活性和清晰性。
5、构造方法
构造方法在使用
new
关键字创建对象时自动调用,它负责初始化新对象的实例变量。每个类可以有一个或多个构造方法,可以根据参数的不同实现重载多个构造方法。以下是构造方法的几个重要特点:
- 构造方法的名称与类名相同,且没有返回类型。
- 构造方法可以有零个或多个参数,这取决于你的需求。
- 构造方法可以重载,即在同一个类中可以有多个具有不同参数的构造方法。
- 如果没有显式定义构造方法,Java会提供一个默认的无参构造方法(即没有参数的构造方法),该构造方法什么也不做。
public class Person {
private String name;
private int age;
public Person() {
// 无参构造方法
// 可以在这里对实例变量进行默认初始化
}
public Person(String name, int age) {
// 带有参数的构造方法
this.name = name;
this.age = age;
}
// getter 和 setter 方法省略...
public static void main(String[] args) {
// 使用构造方法创建对象
Person person1 = new Person(); // 调用无参构造方法
Person person2 = new Person("John", 30); // 调用带有参数的构造方法
}
}
在上面的示例中,
Person
类有两个构造方法:一个是无参构造方法,另一个是带有参数的构造方法。通过使用不同的构造方法,可以在创建对象时提供不同的参数。构造方法根据提供的参数来初始化实例变量,并返回一个新的对象。构造方法在Java中非常重要,它允许在创建对象时进行初始化操作,并为对象的实例变量赋初始值。
6、构造方法重载
在Java中,构造方法可以进行重载。构造方法重载是指在同一个类中定义多个构造方法,这些构造方法拥有相同的名称但参数列表不同。通过使用不同的参数列表,可以实现不同的对象初始化逻辑。
构造方法重载的特点如下:
- 构造方法重载必须在同一个类中进行。
- 重载的构造方法必须具有不同的参数列表,即参数的个数、类型或顺序至少有一个不同。
- 重载的构造方法可以有不同的访问修饰符(如public、private、protected或默认),但它们必须具有相同的名称。
- 调用构造方法时,编译器会根据参数列表的不同选择匹配的构造方法进行调用。
public class Person {
private String name;
private int age;
public Person() {
// 无参构造方法
// 可以在这里对实例变量进行默认初始化
}
public Person(String name) {
// 带有一个参数的构造方法
this.name = name;
}
public Person(String name, int age) {
// 带有两个参数的构造方法
this.name = name;
this.age = age;
}
// getter 和 setter 方法省略...
public static void main(String[] args) {
Person person1 = new Person(); // 调用无参构造方法
Person person2 = new Person("John"); // 调用带有一个参数的构造方法
Person person3 = new Person("Jane", 25); // 调用带有两个参数的构造方法
}
}
在上面的示例中,
Person
类定义了三个构造方法:一个是无参构造方法,一个是带有一个参数的构造方法,另一个是带有两个参数的构造方法。通过不同的构造方法,可以在创建对象时提供不同的参数进行初始化。构造方法的重载使得我们可以根据实际需求创建不同参数的对象,提供了灵活性和便利性。
7、static静态
在Java中,
static
是一个关键字,用于定义静态成员,包括静态变量和静态方法。静态成员属于类而不是对象,它们在类加载时被初始化,并且可以通过类名直接访问,而不需要创建类的实例。下面是关于静态成员的一些重要特点和用法:
静态变量:使用
static
关键字声明的变量是静态变量,也称为类变量。静态变量在类加载时被初始化,只有一份内存空间,所有该类的对象共享同一个静态变量的值。
public class MyClass {
public static int count;
public static void main(String[] args) {
MyClass.count = 5; // 直接通过类名访问静态变量
System.out.println(MyClass.count); // 输出: 5
}
}
静态方法:使用
static
关键字声明的方法是静态方法,它们可以直接通过类名调用,无需创建类的实例。静态方法不能访问实例变量,因为它们不依赖于任何特定的对象实例。
public class MyClass {
public static void sayHello() {
System.out.println("Hello!");
}
public static void main(String[] args) {
MyClass.sayHello(); // 直接通过类名调用静态方法
}
}
静态代码块:使用
static
关键字声明的代码块称为静态代码块,它在类加载时执行,并且只执行一次。静态代码块常用于进行类的初始化操作。
public class MyClass {
static {
System.out.println("Static block executed.");
}
}
静态导入:使用
import static
语句可以导入类的静态成员,以便可以直接使用静态成员的名称,而无需使用类名进行限定。
import static java.lang.Math.PI;
public class MyClass {
public static void main(String[] args) {
double radius = 5.0;
double area = PI * radius * radius; // 直接使用静态导入的 PI
System.out.println("Area: " + area);
}
}
静态成员在一些情况下非常有用,例如用于统计共享数据、提供工具方法等。需要注意的是,静态成员在内存中存在一直到程序结束。但是,过度使用静态成员可能导致代码耦合性增加,降低代码的可测试性和可维护性,因此在使用静态成员时应谨慎权衡。
8、包和导包
在Java中,包(Package)是一种用来组织和管理类和接口的机制。它可以将相关的类和接口放在同一个包中,以提供更好的代码组织和管理。
包的主要作用包括:
命名空间管理:包可以避免类名的冲突,因为不同包中的类可以使用相同的名称,只要它们在不同的包中。通过使用包名,可以在代码中引用具体的类时提供更清晰、更有意义的命名空间。
访问控制:包可以实现对类、接口和成员的访问控制。Java中的访问修饰符(如public、protected、private)可以用于限制包内或包外的访问权限,从而实现封装和安全控制。
代码组织:包可以根据功能、模块或层次等因素组织代码。将相关类和接口放在同一个包中,可以更好地组织和管理代码结构,使代码更易读、易维护和可扩展。
在Java中,包的声明通常在文件的开头,使用
package
关键字。例如:
package com.example.myapp;
这个例子中,
com.example.myapp
是包的名称。包名通常遵循反转的域名(Reverse Domain Name)命名规则,以确保唯一性,避免与其他组织或项目产生冲突。导包(Import)是指在Java代码中引入其他包中的类、接口或静态成员,以便在当前代码中直接使用它们,而不需要使用完整的包名进行限定。导包通过使用
import
关键字实现。例如,假设有一个名为
com.example.util.StringUtils
的类,在其他代码中引用它时可以使用导包方式:
import com.example.util.StringUtils;
public class MyClass {
public static void main(String[] args) {
String str = "Hello";
String reversed = StringUtils.reverse(str);
System.out.println(reversed);
}
}
这里使用
import com.example.util.StringUtils
导入了com.example.util
包中的StringUtils
类。这样在代码中就可以直接使用StringUtils.reverse()
方法,而无需使用完整的包名进行限定。可以使用通配符
*
来导入一个包中的所有类和接口:
import com.example.util.*;
但是,需要注意的是过度使用通配符导入可能会导致命名冲突和代码可读性下降,因此最好只导入需要使用的具体类和接口。
需要注意的是,Java标准库的核心类会自动导入,无需显式导入。例如,
java.util
、java.lang
等包中的类可以直接使用,无需导入。总而言之,包和导包是Java中用于组织、管理和引用类和接口的重要机制,可以提高代码的可读性、可组织性和可维护性。
9、访问权限
在Java中,有四种访问权限修饰符用于控制类、接口、成员变量和方法的访问级别。这些访问权限修饰符决定了其他类或代码是否可以访问给定元素。以下是这些权限修饰符:
public: 最高级别的访问权限修饰符。使用public修饰的类、接口、成员变量和方法可以被任何其他类或代码访问,无论它们是否位于相同的包中。
protected: 使用protected修饰的成员(成员变量和方法)可以被同一包中的其他类访问,以及其他包中的子类访问。注意,对于非子类的其他包中的类,只能访问该类的实例对象而不能直接访问protected成员。
默认(没有修饰符): 如果没有使用任何访问权限修饰符,则该成员具有默认访问级别。默认访问级别意味着成员变量和方法可以被同一包中的其他类访问,但不能被其他包中的类访问。
private: 使用private修饰的成员只能被定义该成员的类内部访问,其他任何类都无法访问。private修饰符提供最严格的访问控制,用于实现封装和数据隐藏。
下表总结了不同访问权限修饰符的可见性范围:
访问权限修饰符 | 当前类 | 同一包 | 不同包的子类 | 不同包的非子类 |
---|---|---|---|---|
public | ✔ | ✔ | ✔ | ✔ |
protected | ✔ | ✔ | ✔ | ✘ |
默认 | ✔ | ✔ | ✘ | ✘ |
private | ✔ | ✘ | ✘ | ✘ |
需要注意一些规则:
- 类的访问权限修饰符只能是public或默认。如果声明为public,则类可以从任何地方访问。如果没有任何修饰符,则类只能在同一包中访问。
- 接口的访问权限修饰符只能是public或默认,与类类似。
- 外部类和内部类之间有一些额外的访问规则。内部类可以直接访问外部类的成员,而外部类不能直接访问内部类的成员。这些规则根据访问权限修饰符的规则进行扩展。
访问权限修饰符是Java中实现封装、隐藏实现细节并提供访问控制的重要机制。通过合理使用这些修饰符,可以控制代码的可见性和访问级别,提高代码的安全性和可维护性。
10、getter和setter
在Java中,getter和setter是用于访问和修改类的私有成员变量(private field)的方法。这种机制允许类通过公共方法来间接操作私有成员变量,以提供封装和数据隐藏。通常情况下,getter用于获取私有成员变量的值,而setter用于设置私有成员变量的值。
Getter方法:
Getter方法是一种公共方法,用于获取私有成员变量的值。它通常遵循一定的命名规范,以"get"开头,后跟首字母大写的成员变量名。Getter方法不接受任何参数,并返回成员变量的值。以下是一个示例:
private String name;
public String getName() {
return name;
}
Setter方法:
Setter方法也是一种公共方法,用于设置私有成员变量的值。它通常遵循一定的命名规范,以"set"开头,后跟首字母大写的成员变量名。Setter方法接受一个参数,表示要设置的新值,通常与成员变量的类型匹配。以下是一个示例:
private String name;
public void setName(String newName) {
name = newName;
}
使用getter和setter方法,可以在其他类中访问和修改私有成员变量,同时还可以对访问进行控制和验证。例如,可以在setter方法中添加一些条件检查来确保设置的值符合特定要求,或者在getter方法中进行计算或格式化。这种封装性使得类中的实现细节对外隐藏,同时提供了更好的代码可维护性和安全性。
需要注意的是,并非所有私有成员变量都需要提供getter和setter方法。有时候可以根据需求将某些成员变量定义为只读或只写,并相应地提供getter或setter方法,以避免对数据进行不必要的访问和修改。