目录
1.面向对象的认识
1.1什么是面向对象
Java是一门纯面向对象的语言(简称OOP),在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。用面向对象的思想来涉及程序,更符合人们对事物的认知,对于大型程序的设计、扩展以及维护都非常友好。
1.2面向对象和面向过程
举个例子,我们就拿洗衣服来说。以前我们在手搓衣服的时候,都要经历准备洗衣服的盆子->放水->放衣服->放洗衣粉->手搓->换水->手搓->拧干->晾衣服等过程。这种传统的方式,注重的是洗衣服的过程。但是对于不同衣服,我们要洗的方式,时间以及怎么拧干都不同,处理起来比较麻烦,如果按照这种方式来写我们的代码,对于之后的扩展和维护都会很麻烦。
所以现在大家普遍都使用洗衣机洗衣服,我们只需将衣服放进洗衣机,加入洗衣粉,启动洗衣机,然后洗衣机就能完成洗衣服的工作并脱水。这一系列是由:人、衣服、洗衣粉、洗衣机,四个对象之间交互完成的。而我们并不需要关心洗衣机到底是怎么洗衣服的,又是如何甩干的,只需将衣服和洗衣粉放进洗衣机,再启动开关即可,是通过对象之间的交互来完成的。
我们所说的传统手搓衣服就是面向过程,而用洗衣机洗衣服就是面向对象了。
面向过程的编程主要关注的是过程,面向对象的编程是指对象与对象之间协作完成,关注的是对象。
不过需要注意的是:面向过程和面向对象并不是一门语言,而是解决问题的方法,没有好坏之分,都有其专门的应用场景。
2.类的定义和使用
2.1认识类
类是用来描述对象的。我们上述提到的洗衣机,它的某个品牌在java中可以看作是一个类别,而每台洗衣机都会有品牌、型号、功率、容量等这些属性,还有它洗衣服的功能。对洗衣机属性的描述,我们把这个过程称为对洗衣机对象(实体)进行抽象,就像开发人员可以采用某种面向对象的编程语言来进行描述,比如:java。
2.2类的定义
在java中定义类要用到关键字:class。
一个类中可以包含:字段(属性/成员变量),成员方法。
字段:一般定义在类中,方法的外面。
我们定义一个狗类来作为例子:
class Dog {
public String name;
public int age;
public void bark() {
System.out.println(name + "在汪汪叫");
}
}
这段代码中class是定义类的关键字,Dog是类的名字,{}中是类的主体。name和age是字段,bark()是成员方法。
类可以理解为自定义类型。
注意:
- 类名必须采用大驼峰
- 成员前写法统一为public
- 此处写的方法不带static
- 一般一个文件中只定义一个类
- main方法所在的类一般要用public修饰
- public修饰的类必须要和文件名相同
- 不要随便修改public修饰类的名称
3.类的实例化
3.1什么是实例化
由类生成对象的过程叫作实例化。java中使用关键字new对对象进行实例化。
那我们来对上面我们创建的狗类进行实例化:
public class test {
public static void main(String[] args) {
Dog dog1 = new Dog();
dog1.name = "小黄";
dog1.age = 3;
dog1.bark();
Dog dog2 = new Dog();
dog2.name = "小黑";
dog2.age = 4;
dog2.bark();
}
}
输出的结果是:
注意:
- new关键字用于创建一个对象的实例
- 使用“ . ”来访问对象中的属性和方法(通过对象的引用可以访问对象的成员变量,同时也可以访问对象的成员方法)
- 同一个类可以创建多个实例
3.2类和对象的说明
- 类只是一个模型一样的东西,用来对一个实体进行描述,限定了类有哪些成员
- 类是一种自定义的类型,可以用来定义变量
- 一个类可以实例化多个对象,实例化出的对象占用实际的物理空间,存储成员变量
4.this引用
4.1为什么要有this 引用
首先我们先创建一个Date类:
class Date {
public int year;
public int month;
public int day;
public void setDay(int y, int m, int d) {
year = y;
month = m;
day = d;
}
public void getDay() {
System.out.println(year + "/" + month + "/" + day);
}
}
第一个方法中我们采用形参赋值的方式给对象进行初始化,此时我们的形参是y, m, d,那么如果我们把形参改成和成员变量名相同的year, month, day会怎样呢?
public void setDay(int year, int month, int day) {
year = year;
month = month;
day = day;
}
很显然最后运行出来肯定不可能按照我们的预期完成日期的初始化,那这是什么原因呢?
- 当成员方法中形参和成员变量名相同,形参自己给自己赋值,并没有修改对象中的值。是因为此时在方法内,形参都是局部变量,局部变量优先使用。
那么如果我们非要让形参和成员变量名相同,这个时候就需要用到this引用
public void setDay(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
此时就可以正常对对象进行初始化了。
那么当我们在实例化多个对象的时候,date1和date2两个对象都在调用setDay和getDay方法,如下:
public static void main(String[] args) {
Date date1 = new Date();
Date date2 = new Date();
date1.setDay(2005, 06, 06);
date1.getDay();
date2.setDay(2000, 02, 14);
date2.getDay();
}
那么问题来了,这么多对象都调用了同一个setDay方法,该怎么区分是哪个对象调用的setDay方法中的year, month, day?
这个时候就需要this来解决这个问题了。
4.2什么是this引用
this代表当前对象的引用,哪个对象的引用调用了该方法,this就代表哪个对象。
上述date1调用了setDay方法,此时该方法里的this就代表了date1对象。
那么this是如何传递的呢?
其实this就是隐藏的第一个参数。
public void setDay(Date this, int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
this的三种用法:
- 可以通过this访问 当前对象的成员变量
- 可以通过this访问 当前对象的非静态的成员方法
- 可以通过this访问 当前对象的其他构造方法
注意:
- this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型
- this只能在“成员方法”中使用(不能在静态方法中使用)
- 在“成员方法”中,this只能引用当前对象,不能再引用其他对象
- this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责接收
5.对象的初始化及构造
5.1对象的初始化
我们先来简单定义一个变量a:
public static void main(String[] args) {
int a;
System.out.println(a);
}
直接输出得到的结果是:
可见局部变量不进行初始化无法通过编译。
那么我们再来看下一段代码:
class Date {
public int year;
public int month;
public int day;
public void setDay(Date this, int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public void getDay() {
System.out.println(this.year + "/" + this.month + "/" + this.day);
}
}
public class test2 {
public static void main(String[] args) {
Date date = new Date();
date.getDay();
}
}
我们在不给成员变量赋任何初始值的情况下输出的结果是:
我们可以得到:成员变量会有一个默认的初始值,可以不进行初始化,而局部变量必须先初始化。
5.2构造方法
构造方法是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期只调用一次。
普通方法和构造方法的区别:
以上述Date类为例,构造方法为:
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
实例化对象的时候可以调用构造方法对对象进行初始化,如:
public static void main(String[] args) {
Date date = new Date(2005, 06, 06);
}
在实例化对象的时候一定会调用构造方法。
上面提到可以通过this引用访问当前对象的其他构造方法,需要注意的是this( ),必须在第一行!!如:
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public Date() {
this(2005, 06, 06);
}
注意:
- 构造方法名字必须与类名相同
- 没有返回值类型,设置为void也不行
- 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
- 构造方法是可以发生重载的,可以有多个构造方法(名字相同,参数列表不同就可以构成方法的重载)
- 当没写任何构造方法的时候,Java会提供一个不带参数的构造方法,但一旦有其他构造方法,就不会提供了。
- 构造方法中,可以通过this调用其他构造方法来简化代码且this(…)必须是构造方法中的第一条语句。不能形成环!!(两个构造方法中不能互相用this来调用对方)
- 绝大多数情况下使用public来修饰,特殊情况下会被private修饰
6.封装
6.1封装的概念
面向对象的程序三大特征:封装、继承、多态。类和对象阶段主要研究封装。封装就是将数据和操作数据的方法有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
简单来说封装就是对外隐藏类内部的实现细节。
6.2访问限定符
java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,更符合人类对事物的认知,而访问权限用来控制方法或者字段能否直接在类外使用。如下:
说明:
- protected主要用在继承中
- default即什么都不写,为默认权限
- 访问权限除了可以限定类中的成员的可见性,也可以控制类的可见性
注意:一般情况下成员变量设置为private,成员方法设置为public。
7.static成员
7.1static修饰成员变量
static修饰的成员变量,称为静态成员变量。静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。
静态成员变量的特性:
- 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中
- 既可以通过对象访问,也可以通过类名访问,一般更推荐使用类名访问
- 静态成员变量也叫类变量,存储在方法区中
- 生命周期伴随类的一生(随类的加载而创建,随类的卸载而销毁)
代码示例:
class Students {
public String name;
public String gender;
public int age;
public static String classRoom = "B03";
public Students(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
}
public class student {
public static void main(String[] args) {
Students stu1 = new Students("xiaoyi", "female", 19);
Students stu2 = new Students("xiaoming", "male", 20);
Students stu3 = new Students("huahua", "female", 19);
//被static修饰,可以直接通过类名访问
System.out.println(Students.classRoom);
}
}
7.2static修饰成员方法
java中,被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的。静态成员一般是通过静态方法来访问的。如:
class Students {
public static String classRoom = "B03";
public static String getClassRoom() {
return classRoom;
}
}
静态方法特性:
- 不属于某个具体的对象,是类方法
- 可以通过对象调用,也可以通过类名.静态方法名()方式调用,更推荐后者
- 不能在静态方法中访问任何非静态成员变量
- 静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用
总结:在静态方法中不能直接使用任何非静态的成员变量和成员方法。要想使用,要通过new对象,然后通过对象的引用访问。但是在非静态成员方法中,可以直接使用静态的成员方法或静态的成员变量。
8.代码块
8.1普通代码块
定义在方法中的代码块,如:
public static void main(String[] args) {
{
int a = 10;
System.out.println("a = " + a);
}
}
8.2构造代码块
定义在类中的代码块,也叫实例代码块。构造代码块一般用于初始化实例成员变量。如:
class Cat {
public String name;
public int age;
//实例代码块
{
this.name = "xiaoming";
this.age = 4;
}
}
8.3静态代码块
使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量。
class Students {
public static String classRoom;
//静态代码块
static {
classRoom = "A06";
}
}
8.4总结
当多个代码块同时存在时,运行顺序:静态代码块>实例代码块(和定义顺序无关)
同一代码块的运行结果与定义顺序有关。
注意:
- 静态代码块不管生成多少个对象,其只会执行一次
- 静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
- 如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行
- 实例代码块只有在创建对象时才会执行