面向对象编程的概念
什么是对象?
什么是对象,简单的说:万物皆对象。车是对象、人数对象、鸟是对象等等。对象也可以说是具有一系列特征(属性)和行为的事或物,比如人有五官这是特征,亦是人的属性;人可以吃穿行走,这是人的行为。
什么是面向对象?
面向对象指以属性和行为的观点去分析现实生活中的事物。
什么是面向对象编程?
面向对象编程指先以面向对象的思想进行分析,然后使用面向对象的编程语言进行表达的过程。
Java中的类和对象
类的概念
类简单来就是“分类”,是对具有相同特征和行为的多个对象共性的抽象描述,在Java语言中体现为一种引用数据类型,里面包含了描述特征/属性的成员变量以及描述行为的成员方法。
Java中的对象
对象主要指现实生活中客观存在的实体,在Java语言中对象体现为内存空间中的一块存储区域。
TIPS:
类是用于构建对象的模板,对象的数据结构由定义它的类来决定。l类是对象的泛指,对象是类的个体。
类的定义
Java中的类的定义如下:
修饰词 class 类名 {
/*定义成员变量*/
修饰词 数据类型 成员变量名 = 初始值;
/*定义行为(方法)*/
修饰词 返回值类型 方法名([方法参数]) {
/*方法体*/
}
}
示例:
public class PersonClass {
private String myName;
public void setName(String myName) {
this.myName= myName;
}
}
TIPS:
public 和 private 是修饰词,之后同一规整。
由上可知:类的成员变量不一定要初始化。
编程规范:
类名中的所有单词的首字母均要大写
成员变量名和方法名要满足驼峰命名
对象的创建
示例:
//语法格式
类名 变量名 = new 类名();
//示例
PersonClass person = new PersonClass();
TIPS:
- 当一个类定义完毕后,可以使用new关键字来创建该类的对象,这个
过程叫做类的实例化。- 创建对象的本质就是在内存空间的堆区申请一块存储区域,用于存放
该对象独有特征信息。
Java中的方法和简易的封装
构造方法(构造器)
示例:
public class Person {
String name;
//无参构造方法
public Person(){}
//有参构造器
public Person(String name) {
this.name = name;
}
}
构造方法,顾名思义构造对象所用的方法,再上述中创建对象时,就用到了无参构造方法。
示例:
public class Test{
public static void main() {
//是用无参构造器创建对象
Person lisi = new Person();
//使用有参构造器创建对象
Person wangwu = new Person("王五");
}
}
TIPS:
- 构造方法名与类名完全相同并且没有返回值类型,连void都不许有。
- 当一个类中没有定义任何构造方法时,编译器会自动添加一个无参空构造构造方法,叫做默认/缺省构造方法。
- 若类中出现了构造方法,则编译器不再提供任何形式的构造方法。
普通方法
格式如下:
public class Person {
/**
* 普通方法
*/
修饰词 返回值类型 方法名([方法参数]) {
/*方法体*/
}
}
TIPS:
方法的重载
- 若方法名称相同,参数列表不同,这样的方法之间构成重载关系(Overload)。
- 方法重载的主要形式体现在:参数的个数不同、参数的类型不同、参数的顺序不同,与返回值类型和形参变量名无关,但建议返回值类型最好相同。
- 判断方法能否构成重载的核心:调用方法时能否加以区分。
- 方法重载的实际意义在于调用者只需要记住一个方法名就可以调用各种不同的版本,来实现各种不同的功能。
this关键字
this关键字的基本概念
- 若在构造方法中出现了this关键字,则代表当前正在构造的对象。
- 若在成员方法中出现了this关键字,则代表当前正在调用的对象。
- this关键字本质上就是当前类类型的引用变量。
this关键字工作原理
- 在构造方法中和成员方法中访问成员变量时,编译器会加上this.的前缀,而this.相当于汉语中"我的",当不同的对象调用同一个方法时,由于调用方法的对象不同导致this关键字不同,从而this.方式访问的结果也就随之不同。
this关键字的简易使用方式
- 当局部变量名与成员变量名相同时,在方法体中会优先使用局部变量(就近原则),若希望使用成员变量,则需要在成员变量的前面加上this.的前缀,明确要求该变量是成员变量。
- this关键字除了可以通过this.的方式调用成员变量和成员方法外,还可以作为方法的返回值。
- 在构造方法的第一行可以使用this()的方式来调用本类中的其它构造方法。
this使用的示例
public class Person {
private String name;
public Person() {
/**
* 构造器中使用this关键字,代表当前正在构造的对象
*/
this("李四");
}
public Perosn(String name) {
/**
* 构造器中使用this关键字,代表当前正在构造的对象
*/
this.name = name;
}
public String getName() {
/**
* 成员方法中出现了this关键字,则代表当前正在调用的对象
*/
return this.name;
}
}
注意事项:
- 引用类型变量用于存放对象的地址,可以给引用类型赋值为null,表示不指向任何对象。
- 当某个引用类型变量为null时无法对对象实施访问(因为它没有指向任何对象)。此时,如果通过引用访问成员变量或调用方法,会产生NullPointerException异常。
封装(简易理解)
封装的概念
- 通常情况下可以在测试类给成员变量赋值一些合法但不合理的数值,无论是编译阶段还是运行阶段都不会报错或者给出提示,此时与现实生活不符。
- 为了避免上述错误的发生,就需要对成员变量进行密封包装处理,来隐藏成员变量的细节以及保证成员变量数值的合理性,该机制就叫做封装。
封装的实现流程
- 私有化成员变量,使用private关键字修饰。
- 提供公有的get和set方法,并在方法体中进行合理值的判断。
- 在构造方法中调用set方法进行合理值的判断。
Java中的修饰词和继承
继承的概念
- 当多个类之间有相同的特征和行为时,可以将相同的内容提取出来组成一个公共类,让多个类吸收公共类中已有特征和行为而在多个类型只需要编写自己独有特征和行为的机制,叫做继承。
- 在Java语言中使用extends(扩展)关键字来表示继承关系。
- 如:
public class Worker extends Person{} -表示Worker类继承自Person类
其中Person类叫做超类、父类、基类。
其中Worker类叫做派生类、子类、孩子类。 - 使用继承提高了代码的复用性,可维护性及扩展性,是多态的前提条件。
继承的特点
- 子类不能继承父类的构造方法和私有方法,但私有成员变量可以被继承只是不能直接访问。
- 无论使用何种方式构造子类的对象时都会自动调用父类的无参构造方法,来初始化从父类中继承的成员变量,相当于在构造方法的第一行增加代码super()的效果。
- 使用继承必须满足逻辑关系:子类is a 父类,也就是不能滥用继承。
- Java语言中只支持单继承不支持多继承,也就是说一个子类只能有一个父类,但一个父类可以有多个子类。
Java中的修饰词
static
static可以修饰成员变量,也可以修饰方法,使用static关键字来进行修饰表示静态的含义,此时被修饰的对象(成员变量/方法)由对象层级提升为类层级,也就是整个类只有一份并被所有对象共享,该成员变量/方法随着类的加载准备就绪,与是否创建对象无关。static关键字修饰的成员变量/方法可以使用引用.的方式访问,但推荐类名.的方式。
示例:
public class Person {
public static String name = "小黑";
public static show() {
System.out.println("我相信凹凸曼,我相信光!");
}
}
//使用被static修饰的成员变量和方法
public class Test {
public static void main(String[] args) {
//创建Person对象
Person p = new Person();
//推荐
String name = Person.name;
//String name = p.name;//不推荐
//推荐
Person.show();
//p.show();//不推荐
}
}
使用限制
- 在非静态成员方法中既能访问非静态的成员又能访问静态的成员。
(成员:成员变量+ 成员方法,静态成员被所有对象共享)- 在静态成员方法中只能访问静态成员不能访问非静态成员。
(成员:成员变量+ 成员方法,因为此时可能还没有创建对象)- 在以后的开发中只有隶属于类层级并被所有对象共享的内容才可以使用static关键字修饰。(不能滥用static关键字)
构造块和静态代码块(熟悉)
构造快在类体中直接使用{}括起来的代码块。每创建一个对象都会执行一次构造块。
public class Person {
//构造块
{
System.out.println("我是构造块,每次创建对象都会执行");
}
}
静态代码块使用static关键字修饰的构造块。静态代码块随着类加载时执行一次。
public class Person {
//静态代码块
static {
System.out.println("我是静态代码块,只在类加载时执行一次");
}
}
单例设计模式
单例设计模式的概念
在某些特殊场合中,一个类对外提供且只提供一个对象时,这样的类叫做单例类,而设计单例的流程和思想叫做单例设计模式。
单例设计模式的实现流程
- 私有化构造方法,使用private关键字修饰。
- 声明本类类型的引用指向本类类型的对象,并使用private static关键字共同修饰。
- 提供公有的get方法负责将对象返回出去,并使用public static关键字共同修饰。
单例设计模式的实现方式
单例设计模式的实现方式有两种:饿汉式和懒汉式,在以后的开发中推荐饿汉式。
饿汉式实现:
public class Single {
//将构造函数私有化
private Single(){}
//声明本类类型的引用指向本类类型的对象,并使用private static关键字共同修饰。
private static final Single s = new Single();
//提供公有的get方法负责将对象返回出去,并使用public static关键字共同修饰。
public static Single getInstance() {
return s;
}
}
懒汉式实现:
class Single {
private Single(){}
private static Single s;
public static Single getInstance() {
if(s == null) {
s = new Single();
}
return s;
}
}
饿汉式和懒汉式的区别:
(1) 饿汉式是类一加载进内存就创建好了对象;
(2) 懒汉式则是类才加载进内存的时候,对象还没有存在,只有调用了 getInstance()方法时,对象才开始创建。
final
基本概念
final本意为"最终的、不可改变的",可以修饰类、成员方法以及成员变量。
使用方法
- final关键字修饰类体现在该类不能被继承。
-主要用于防止滥用继承,如:java.lang.String类等。 - final关键字修饰成员方法体现在该方法不能被重写但可以被继承。
-主要用于防止不经意间造成重写,如:java.text.Dateformat类中format方法等。 - final关键字修饰成员变量体现在该变量必须初始化且不能改变。
-主要用于防止不经意间造成改变,如:java.lang.Thread类中MAX_PRIORITY等。
常量的概念
- 在以后的开发中很少单独使用final关键字来修饰成员变量,通常使用public static final关键字共同修饰成员变量来表达常量的含义,常量的命名规范要求是所有字母都要大写,不同的单词之间采用下划线连。
- public static final double PI = 3.14;
访问控制
常用的访问控制符
修饰符 | 本类 | 同一个包中的类 | 子类 | 其他类 |
---|---|---|---|---|
public | 可以访问 | 可以访问 | 可以访问 | 可以访问 |
protected | 可以访问 | 可以访问 | 可以访问 | 不能访问 |
默认 | 可以访问 | 可以访问 | 不能访问 | 不能访问 |
private | 可以访问 | 不能访问 | 不能访问 | 不能访问 |
注意事项
- public修饰的成员可以在任意位置使用。
- private修饰的成员只能在本类内部使用。
- 通常情况下,成员方法都使用public关键字修饰,成员变量都使用private关键字修饰。
多态
多态
多态的概念
多态主要指同一种事物表现出来的多种形态。
多态的语法格式
父类类型引用变量名= new 子类类型();
多态的特点
- 当父类类型的引用指向子类类型的对象时,父类类型的引用可以直接调用父类独有的方法。
- 当父类类型的引用指向子类类型的对象时,父类类型的引用不可以直接调用子类独有的方法。
- 对于父子类都有的非静态方法来说,编译阶段调用父类版本,运行阶段调用子类重写的版本(动态绑定)。
- 对于父子类都有的静态方法来说,编译和运行阶段都调用父类版本。
引用数据类型之间的转换
- 引用数据类型之间的转换方式有两种:自动类型转换和强制类型转换。
- 自动类型转换主要指小类型向大类型的转换,也就是子类转为父类,也叫做向上转型。
- 强制类型转换主要指大类型向小类型的转换,也就是父类转为子类,也叫做向下转型或显式类型转换。
- 引用数据类型之间的转换必须发生在父子类之间,否则编译报错。
- 若强转的目标类型并不是该引用真正指向的数据类型时则编译通过,运行阶段发生类型转换异常。
- 为了避免上述错误的发生,应该在强转之前进行判断,格式如下:
if(引用变量instanceof数据类型)
判断引用变量指向的对象是否为后面的数据类型
特殊类
抽象类
抽象方法的概念
- 抽象方法主要指不能具体实现的方法并且使用abstract关键字修饰,也就是没有方法体。
- 具体格式如下:
访问权限abstract 返回值类型方法名(形参列表);
public abstract void cry();
抽象类的概念
- 抽象类主要指不能具体实例化的类并且使用abstract关键字修饰,也就是不能创建对象。
抽象类和抽象方法的关系
- 抽象类中可以有成员变量、构造方法、成员方法;
- 抽象类中可以没有抽象方法,也可以有抽象方法;
- 拥有抽象方法的类必须是抽象类,因此真正意义上的抽象类应该是具有抽象方法并且使用abstract关键字修饰的类。
抽象类的实际意义
- 抽象类的实际意义不在于创建对象而在于被继承。
- 当一个类继承抽象类后必须重写抽象方法,否则该类也变成抽象类,也就是抽象类对子类具有强制性和规范性,因此叫做模板设计模式。
示例:
/**
* 抽象类
*/
public abstract class Person {
//成员变量
private String name;
//构造方法
public Person(){
System.out.println("抽象方法的无参构造方法");
}
//成员方法
public String getName() {
return name;
}
//抽象方法
public abstract String show();
}
接口
接口的基本概念
- 接口就是一种比抽象类还抽象的类,体现在所有方法都为抽象方法。
- 定义类的关键字是class,而定义接口的关键字是interface。
类和接口之间的关系
名称 | 关键字 | 关系 |
---|---|---|
类和类之间的关系 | 使用extends关键字表达继承关系 | 支持单继承 |
类和接口之间的关系 | 使用implements关键字表达实现关系 | 支持多实现 |
接口和接口之间的关系 | 使用extends关键字表达继承关系 | 支持多继承 |
抽象类和接口的主要区别:
- 定义抽象类的关键字是abstract class,而定义接口的关键字是interface。
- 继承抽象类的关键字是extends,而实现接口的关键字是implements。
- 继承抽象类支持单继承,而实现接口支持多实现。
- 抽象类中可以有构造方法,而接口中不可以有构造方法。
- 抽象类中可以有成员变量,而接口中只可以有常量。
- 抽象类中可以有成员方法,而接口中只可以有抽象方法。
- 抽象类中增加方法时子类可以不用重写,而接口中增加方法时实现类需要重写(Java8以前的版本)。
- 从Java8开始增加新特性,接口中允许出现非抽象方法和静态方法,但非抽象方法需要使用default关键字修饰。
- 从Java9开始增加新特性,接口中允许出现私有方法。
内部类
内部类的基本概念
- 当一个类的定义出现在另外一个类的类体中时,那么这个类叫做内部类(Inner),而这个内部类所在的类叫做外部类(Outer)。
- 类中的内容:成员变量、成员方法、构造方法、静态成员、构造块和静态代码块、内部类。
内部类的作用
- 当一个类存在的价值仅仅是为某一个类单独服务时,那么就可以将这个类定义为所服务类中的内部类,这样可以隐藏该类的实现细节并且可以方便的访问外部类的私有成员而不再需要提供公有的get和set方法。
内部类的分类
- 普通内部类-直接将一个类的定义放在另外一个类的类体中。
- 普通内部类和普通类一样可以定义成员变量、成员方法以及构造方法等。
- 普通内部类和普通类一样可以使用final或者abstract关键字修饰。
- 普通内部类还可以使用private或protected关键字进行修饰。
- 普通内部类需要使用外部类对象来创建对象。
- 如果内部类访问外部类中与本类内部同名的成员变量或方法时,需要使用this关键字。
public class Person {
//属性
private String name;
//普通内部类
public class PersonType {
private String type;
//内部类构造方法
public PersonType(String type) {
this.type = type;
}
public void show() {
System.out.println("内部类的成员方法");
}
}
}
使用普通内部类
public class Test {
public static void main(String[] args) {
//创建外部类对象
Person person = new Person();
//创建内部类对象
Person.PersonType personType = person.new PersonType("医生");
//使用内部类中的方法
personType.show();
}
}
- 静态内部类-使用static关键字修饰的内部类,隶属于类层级。
- 静态内部类不能直接访问外部类的非静态成员。
- 静态内部类可以直接创建对象。
- 如果静态内部类访问外部类中与本类内同名的成员变量或方法时,需要使用类名.的方式访问。
public class Person {
//静态成员变量
private static String name = "person";
//成员方法
public void show() {
System.out.println("Person.name: " + name);
}
//静态内部类
public static class PersonType {
private String name;
public PersonType(String name) {
this.name = name;
}
public void show() {
//如果静态内部类访问外部类中与本类内同名的成员变量或方法时,需要使用类名.的方式访问
System.out.println("PersonType.name: " + this.name + " " + Person.name);
}
}
}
使用静态内部类
public class Test {
public static void main(String[] args) {
//静态内部类可以直接创建对象
Person.PersonType personType = new Person.PersonType("personType");
personType.show();
}
}
- 局部内部类-直接将一个类的定义放在方法体的内部时。
- 局部内部类只能在该方法的内部可以使用。
- 局部内部类可以在方法体内部直接创建对象。
- 局部内部类不能使用访问控制符和static关键字修饰符。
- 局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的声明周期不同所致。
public class Test {
public static void main(String[] args) {
//final修饰的变量,才可以在局部内部类的使用
final int num = 10;
//局部内部类
class Person {
int age = num;
void show() {
System.out.println(age);
}
}
Person person = new Person();
person.show();
}
}
- 匿名内部类-就是指没有名字的内部类。
示例:
public class Test {
public static void main(String[] args) {
//
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类");
}
};
}
}
枚举
在日常生活中这些事物的取值只有明确的几个固定值,此时描述这些事物的所有值都可以一一列举出来,而这个列举出来的类型就叫做枚举类型。
枚举的定义
- 使用public static final表示的常量描述较为繁琐,使用enum关键字来定义枚举类型取代常量,枚举类型是从Java5开始增加的一种引用数据类型。
- 枚举值就是当前类的类型,也就是指向本类的对象,默认使用public static final关键字共同修饰,因此采用枚举类型.的方式调用。
- 枚举类可以自定义构造方法,但是构造方法的修饰符必须是private,默认也是私有的。
Enum类的概念和方法
- 所有的枚举类都继承自java.lang.Enum类,常用方法如下:
方法 | 描述 |
---|---|
static T[] values() | 返回当前枚举类中的所有对象 |
String toString() | 返回当前枚举类对象的名称 |
intordinal() | 获取枚举对象在枚举类中的索引位置 |
static T valueOf(String str) | 将参数指定的字符串名转为当前枚举类的对象 |
intcompareTo (E o) | 比较两个枚举对象在定义时的顺序 |