文章目录
一、认识面向对象
1.1面向对象和面向过程
面向过程:面向过程即强调过程,比如说我们要做一个大型的项目,我们就把该项目划分为几个功能块(函数),把这几个功能块组合在一起就形成了一个项目,我们重点关注就是这几个函数(方法)。重点强调的就是每一个方法,每一个过程。
面向对象:面向对象即强调对象,比如我们要做一个大型的项目,我们换一种思想,我们找一个对象,该对象具备这几个功能,重点关注的是对象。
面向对象和面向过程的关系:面向对象是基于面向过程的,是建立在面向过程基础之上的。
举例:
面向过程:当我们去旅游的时候,我们需要亲自买机票、车票、门票等等。
面向对象:找一家旅游公司,只需要交钱、他就会帮你全部办好,使我们出行变得更方便了。
面向对象的好处:
- 它是一种更符号我们人类思想习惯的思想
- 可以将复杂的事情简单化
1.2什么是面向对象(Object Oriented)
面向对象是软件开发的一种思想,一种编程风格,面向对象开发方法认为客观世界是由对象组成的, 对象由属性和行为组成。任何对象都可以看做某 一类事物的实例,面向对象的方法主要是把事物给对象化(实例化)。
一类事物:人类、狗类、树类……
对象:一个人、一只狗,一棵树……
属性:人的属性有身高、年龄、姓名、性别……
行为:人会吃、喝、玩、乐……
二、类定义和使用
2.1认识类
类是对现实生活中一类具有共同特征的事物的抽象,描述 一类对象对象的属性和行为。
举例:人类
世界上所有的人统称为人类,人类具有很多的属性和行为,我们每一个个体都是一个对象,不同对象的属性和行为都有所差异。
在Java语言中,是如何定义类的?
2.2类的定义格式
在Java中定义类使用class关键字,定义格式如下👇
class 类名{
field//属性(成员变量或字段)
method//行为(成员方法)
}
class Human{
public String name;
public int age;
public String sex;
public void eat(){
System.out.println(name+":吃东西");//谁吃东西
}
public void sleep(){
System.out.println(name+":睡觉");//谁睡觉
}
}
2.3类的实例化
相当于在计算机中定义了一种新的类型,与Java中的基本类型类似,类是自定义的新类型,我们可以通过这些类,实例出对象,称为类的实例化。
在java中采用new关键字配合类名来实例化对象。
public class Demo {
public static void main(String[] args) {
Human person1 = new Human();
person1.name = "Abel";
person1.eat();
Human person2 = new Human();
person2.name = "Anli";
person2.eat();
Human person3 = new Human();
person3.name = "Kari";
person3.eat();
}
}
注意事项:
- new关键字用于创建一个对象的实例
- 使用.访问对象中的属性和方法
- 一个类可以创建多个实例
2.4类和对象的说明
类就相当于我们设计房子时的一张图纸,只设计出了一些东西,并没有实际的建筑存在,类的实例化相当于使用设计图建造出房子。
- 类相对于模型,可以对一个实体进行描述。
- 类是一种自定类型,可以用来定义变量。
- 一个类可以实例化多个对象,实例化的每一个对象占用实际的物理空间,存储类的成员变量
三、this引用
3.1为什么要this引用
当我们在类中定义的成员变量和成员方法时一般不立即具体化,而是当实例化才开始调用和赋值,
案例引入:日期类
public class Test {
public static void main(String[] args) {
Data data = new Data();
data.setDate(2022,5,20);
data.printData();
}
}
class Data{
public int year;
public int month;
public int day;
public void setDate(int year, int month, int day){
year = year;
month = month;
day = day;
}
public void printData(){
System.out.println(year+"/"+month+"/"+day);
}
}
结果并不是我们想要的!!!
1.形参名和成员变量名相同?
public void setDate(int year, int month, int day){
year = year;
month = month;
day = day;
}
到底是谁给谁赋值呢?成员变量给成员变量?参数给参数?参数给成员变量?成员变量给参数?
可以看出,是参数给了参数!!那么该如何解决呢?
3.2什么是this引用
this引用指向当前对象,哪个对象调用this所在的方法,this就代表哪个对象,可见this的灵活性。
this引用的特性
- 哪个对象调用就是哪个对象的类型
- this只能在非静态成员方法和构造方法中使用
四、对象的构造及初始化
上文我们使用一个方法给对象初始化, 每次需要调用方法初始化,比较繁琐,那么该如何解决呢?
4.1构造方法
构造方法(构造器),是一种特殊的方法,它是一个与类同名的方法,对象的创建就是通过构造方法来完成的,其功能主要完成对象的初始化,由编译器自动调用,并且在整个对象的生命周期内只调用一次。
public class Test {
public static void main(String[] args) {
Data data1 = new Data(2022,5,20);
data1.printData();
Data data2 = new Data(2022,5,21);
data2.printData();
Data data3 = new Data(2022,5,22);
data3.printData();
}
}
class Data{
public int year;
public int month;
public int day;
//构造方法一般情况下用public修饰
public Data(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}
public Data(){
//无参构造方法
}
public void printData(){
System.out.println(this.year+"/"+this.month+"/"+this.day);
}
}
构造方法的特性:
- 名字必须与类名相同
- 没有返回值类型
- 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
- 构造方法也可以重载
- 若用户未定义构造方法,编译器会默认生成一个不带参的构造方法,若用户有定义,编译器则不再生成
4.2构造方法和this
构造方法中,可用通过this调用其他构造方法来简化代码
class Data{
public int year;
public int month;
public int day;
public Data(int year, int month, int day){
this(year,month);
this.day = day;
}
public Data(int year, int month){
this.year = year;
this.month = month;
}
public void printData(){
System.out.println(this.year+"/"+this.month+"/"+this.day);
}
}
注意:
- this(…)必须是构造方法中的第一条语句
- 不能形成环
总结:
- this.成员变量(引用this指向对象的成员变量)
- this(参数列表)调用其他构造方法
- this.成员方法(引用this指向对象的成员方法)
4.3初始化
一个局部变量未初始化,是不能够被使用的,而成员变量可以不初始化就可以使用。
成员变量默认初始化:
数据类型 | 默认值 |
---|---|
byte | 0 |
char | ‘\u0000’ |
short | 0 |
int | 0 |
long | 0L |
float | 0.0f |
double | 0.0 |
boolean | false |
reference | null |
成员变量就地初识化 | |
在定义变量时,就直接给初值 |
class Person{
String name = "maria";
int age = 10;
}
注意:代码编译完成后,编译器会将所有的初始化语句添加到各个构造方法中。
五、代码块
5.1普通代码块
public static void main(String[] args){
//直接使用{}定义,没有什么特殊的作用,比较少见
{
int x = 10;
System.out.println(a);
}
}
5.2构造代码块
构造代码块一般用于初始化实例成员变量。
public class Test {
public static void main(String[] args) {
Student student1 = new Student();
student1.show();
}
}
因为构造代码块是独立的,当我们创建对象时,如果构造代码块和构造方法同时存在时,先执行构造代码块,再执行构造方法。
注意:构造代码块,只要创建一个对象就会执行一次
用途:一般用于初始化实例成员变量
5.3静态代码块
public class Test {
public static void main(String[] args) {
Student student1 = new Student();
student1.show();
Student student2 = new Student();
student2.show();
}
}
静态代码块,用static声明,JVM加载类时执行,所以执行顺序比实例代码块早。
用途:一般用来初始化静态成员变量
注意事项:
- 静态代码块不管类实例化了多少个对象,都只会执行一次
- 如果一个类中包含个静态代码块,再编译代码时,编译器会按照定义的先后顺序依次合并
六、内部类
内部类:一个类定义在另一个类或者一个方法的内部。
6.1实例内部类
定义在类中的类,定义位置与类成员所处的位置相同,也称为成员内部类。
class Demo1{
public static void main(String[] args) {
//创建实例内部类对象方法
//1.外部类名.内部类名 变量名 = new 外部类名().new 内部类名()
OuterClass.InnerClass innerClass1 = new OuterClass().new InnerClass();
//2.先创建外部类对象,在创建内部类对象
OutClass outClass1 = new OutClass();
OutClass.InnerClass innerClass2 = outClass1.new InnerClass();
}
}
总结:
- 外部类的任何成员都可以在实例内部类中访问。
- 实例内部类,也受访问限定符的约束。
- 在实例内部类与外部类成员同名,使用同名的成员时,优先访问自己的,如果要访问外部类同名的成员,外部类名.this.同名成员来访问。
- 实例内部类对象必须先有外部类对象的前提下才能创建。
- 外部类中,不能直接访问实例内部类的成员,要访问必须要创建内部类对象。
- 实例内部类不能有静态的成员方法和成员变量。
6.2静态内部类
使用static修饰的成员内部类
public class Demo {
public static void main(String[] args) {
//1.不需要创建外部类对象即可创建内部类
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
innerClass.print();
}
}
总结:
- 静态内部类只能访问外部类中的静态成员
- 创建外部类对象时,不需要创建外部类对象
6.3局部内部类
定义在方法体或者{}中。
public class Demo {
public static void main(String[] args) {
//编译报错
OutClass.InnerClass innerClass = new OutClass().new InnerClass();
}
}
总结:
- 局部内部类只能在所定义的方法体内部使用
- 只能在方法内部,不存在外部可见性问题,因此不能用访问权限符修饰,static也不能修饰。
- 编译器也会未该类生成独立的字节码文件
- 可以访问外部类的成员变量
- 可以使用final或abstract修饰
6.3匿名内部类
没有名字的局部内部类
为什么要使用匿名内部类?
是Java为了方便我们编写程序而设计的一个机制,往往我们在开发会遇到这样一个情况,一个接口/类的方法只要用到一次,但我们如果要去使用它,我们需要创建它的实现类/子类去实现重写,使用匿名内部类就可以无需创建新的类,就能满足我们的需求,也减少了代码的冗余。
//定义方法
new 接口/类名(参数列表){
实现方法1(){
}
实现方法2(){
}
...
}
例如我们想自定义二维数组排序的规则?
public class Demo {
public static void main(String[] args) {
int[][] array = {{5,1},{2,8},{8,1},{1,6},{5,2}};
Arrays.sort(array, new Comparator<int[]>() {
//1.匿名类中重写compare方法
@Override
public int compare(int[] o1, int[] o2) {
//第一个数不相等则升序排列,若相等,则按第二个数升序排列
if(o1[0] != o2[0]){
return o1[0]-o2[0];
}else {
return o1[1]-o2[1];
}
}
});
System.out.println(Arrays.deepToString(array));
}
}
总结:
- 匿名内部类没有类名
- 匿名内部类不可以声明静态变量(可以访问静态或非静态的成员),
- 匿名内部类不能定义静态的方法
- 匿名内部类不可以定义构造方法(在定义匿名类同时已经实例化对象)
七、抽象类
概念:在面向对象的概念中,所有的对象都是通过类来描述的,但是反过来,并不是所有的类都是用来描述对象的,如果一个类中没有包含足够的信息来描述一个具体的对象,这样的类就是抽象类。
Java当中用Abstract关键字修饰的类,就叫做抽象类。
7.1浅谈为何要有抽象类
根本原因:无法描述一类事物的类
例子引入:比如现在想创建一个动物类,描述动物的一些共性,比如动物会吃东西,但是具体的动物吃的东西不尽相同,而我们在动物类中就很难去描述动物去吃什么东西。采用继承的思想,子类重新该方法,在添加具体的实现。
class Animal{
public void eat(){
}
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃狗粮");
}
}
class Pig extends Animal{
@Override
public void eat() {
System.out.println("猪吃猪粮");
}
}
有的人可能会说这不也很好的实现了吗?
一般的类确实也能满足该需求,抽象类主要是用来适配子类的通用特性,是被用来创建子类的模板,实际上有些父类中的方法没有必要重新,当我们成使用抽象类来定义时,这样就可以区分哪些方法需要重写,具有提示的作用,也是我们设计程序的一种思想,我相信随着我们逐渐深入的学习,对这些设计会感触颇深。
7.2抽象类的特性
总结:
- 抽象类使用abstract关键字修饰
- 包含抽象方法的类一定是抽象类,反之,抽象类不一定包含抽象方法。
- 抽象类必须要被继承使用,否则就没有存在的意义,继承的子类必须重写父类中的抽象方法(子类也是抽象类除外)
- 抽象类不能够实例化
- 抽象方法不能被private(用private修饰的方法,不能被子类重写,那该抽象方法体是空的就没有存在的意义了),static(static修饰的方法是静态的方法,可以直接被类名调用,而抽象类没有具体的方法体,调用没有意义),final(final修饰的方法不能被重写)修饰符修饰。