JAVA自学笔记,面向对象编程。

面向对象编程

大家都知道Java是一门面向对象编程的语言,那么什么是面向对象,它又是怎么兴起的呢?
在程序开发初期,人们使用结构化开发语言,但随着软件的规模越来越庞大,结构化语言的弊端也逐渐暴露出来,开发周期被无休止地拖延,产品的质量也不尽如人意,结构化语言已经不再适合当前的软件开发。这时人们开始讲另一种开发思想引入程序中,即面向对象的开发思想。面向对象思想是人类最自然的一种思考方式,它将所有预处理的问题抽象为对象,同时了解这些对象具有哪些相应的属性以及行为, 以解决这些对象面临的一些实际问题,这样就在程序开发中引入了面向对象设计的概念,面向对象设计实质上就是对现实世界的对象进行建模改造。

对象

在Java的世界中,万物皆对象,这是一个抽象的概念,对象是事务存在的实体,人类解决问题的方式是将复杂的事务简单化,于是就会思考这些对象都是由哪些部分组成的,通常都会将对象划分为两个部分,即静态部分与动态部分。静态部分被称为属性,任何对象都具备其自身的属性,比如一个学生,有姓名,性别,年龄,成绩,学号等。然而具有这些属性的人会执行哪些动作也是一个值得讨论的部分,学生可以吃饭,学习,睡觉,上厕所。人类通过讨论对象的属性和观察对象的行为了解对象。

类是对象的集合,比如可以说鲨鱼是鱼类,但是不能说鱼类是鲨鱼。鲨鱼就是一个具体的对象,而鱼类就是拥有某些相同属性和行为的对象的统称。类是世间万物的抽象统称,而对象则是这个事物相对应的实体。如果面临实际问题,通常需要实例化类对象来解决,比如鲨鱼在吃肉,我们只能拿这只在吃肉的鲨鱼来处理这个问题,而不能拿所有鲨鱼或者整个鱼类来解决。
类是封装对象的属性和行为的载体,反过来说具有相同属性和行为的一类实体被称为类。例如,鱼类封装了所有鱼的共同属性和应具有的行为,
定义完一个鱼类后,可以根据这个类抽象出一个实体对象,最后通过实体对象来解决相关的实际问题。在Java语言中类包括对象的属性和方法。类中对象的属性是以成员变量的形式定义的,对象的行为是以方法的形式定义的。

面向对象程序设计特点。

面向对象程序设计,也就是Java语言的三大特性:继承,封装,多态。

封装

封装是面向对象变成的核心思想。将对象的属性和行为封装起来,其载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想。就好比用户使用计算机时,我们不需要知道计算机的工作原理,我们只需要通过鼠标键盘来操作就可以了。
采用封装的思想保证了类内部数据结构的完整性,应用该类的用户不能轻易地直接操作此程序结构,只能执行类允许公开的数据。这样就避免了外部操作对内部数据的影响,提高了程序的可维护性。

继承

类与类之间同样具有关系,比如学生类与教师类,这两个类中可以有许多相同的方法和属性,比如性别,年龄,需要睡觉,需要吃饭。这个时候我们可以把这些相同的属性集合到另一个类里面。然后让学生和教师继承这个类。我来写个小例子。
JAVA自学笔记,面向对象编程。_第1张图片
我来给大家讲解一下上面代码的意思,首先我创建了一个Person类,它有名字,年龄,性别,三个成员变量。然后又声明了三个成员方法eat,sleep,run。随后我又创建了一个Student类和一个Teacher类,这两个类继承(extends)了Person类,说明他们两个是Person的子类,而Person是他们两个的父类,子类可以拥有父类属性和方法。因为每个学生和老师都有姓名,年龄和性别,并且他们都有吃饭,睡觉,和跑的方法,但是如果分别写在Student类和Teacher类中就会出现大量的重复代码(就像上面的number需要写两遍)。而我把Student和Teacher中相同的属性提取出来放在Person类中,这样可以大大节约代码量,增加效率。

多态

上面介绍了继承,了解了父类和子类,其实将父类对象应用于子类的特征就是多态,多态的实现并不依赖具体类,而是依赖于抽象类和接口。比如上面的Person类我们可以将里面的方法和属性全部定义成抽象的,就是说我们知道这个人有名字有年龄能吃饭,能睡觉,能跑,但是我们不知道他的名字是什么,年龄多大,吃的是什么,在哪里睡的觉,在哪里跑的步。抽象类不能实例化对象,在多态的机制中,抽象类只是给出一个方法的标准,而不给出实现的具体流程。如果将Student类的对象统一看作是Person的实例对象,这样当吃饭时,简单的调用父类的eat方法就可以实现,这就是多态的基本思想。

类和对象

Java中定义类的语法如下。

class 类名称{
类的成员变量
类的成员方法
}

在Java语言中对象的属性以成员变量的形式存在,对象的方法以成员方法的形式存在。

成员变量

在Java中对象的属性也称为成员变量,成员变量的定义与普通变量的定义一样。

数据类型 变量名 [ = 值];

其中,[ = 值]是可选内容,就是说我们可以在定义的时候直接赋值,也可以不赋值。在上面的例子中,可以看到在Java中class关键字用来定义类,Person是类名,其中定义了三个成员变量age,name,sex。成员变量的类型可以设置为Java中合法的数据类型,其实成员变量就是普通的变量,可以为他设置初始值,也可以不设置初始值。如果不设置初始值,则会有默认值。
JAVA自学笔记,面向对象编程。_第2张图片

成员方法

在Java语言中,成员方法对应于类对象的行为,它主要用来定义类可执行的操作,它是包含一系列语句的代码块。
成员方法的定义语句如下。

[权限修饰符] [返回值类型] 方法名([参数类型 参数名])[throw异常类型]{
方法体
return返回值;
}

其中权限修饰符可以使private,public,protected中的任何一个,也可以不写,主要是用来控制方法的访问权限,关于权限修饰符将在后面讲到。返回值类型指定方法返回数据的类型,可以使任何类型,如果方法不需要返回值,则使用void关键字代表无返回值。一个成员方法既可以有参数,也可以没有参数,参数可以使对象也可以是基本数据类型的变量。
在这里插入图片描述
方法的定义必须在某个类中,定义时如果没有指定权限修饰符,方法的访问权限默认为只能在同类以及同包类中访问。
如果定义的方法有返回值,则必须使用return关键字返回一个指定类型的数据,并且返回值类型要与方法返回的值类型一致,
在这里插入图片描述
如果我们把return 1;注释掉的话,IDE工具就会报错。
JAVA自学笔记,面向对象编程。_第3张图片

成员方法的参数

调用方法时可以给该方法传递一个或多个值,传给方法的值叫做实参,在方法的内部,接受实参的变量叫做形参,形参的声明语法与变量的声明语法一样。形参只是在方法内部有效。Java中方法的参数主要有3中,分别为参数值,引用参数,和不定长参数。打个比方,比如你有一个榨汁机,你可以把这个榨汁机想象成需要传递参数的方法,你需要给它里面装水果,他才会给你产出相应的果汁,否则它什么也做不了。
值参数表明实参与形参之间按值传递,当使用参数值的方法被调用时,编译器为形参分配储存单元,然后将对应的实参的值赋值到形参中,由于是值类型的传递方式,所以,在方法中对值类型的形参的修改,不会影响实参。
JAVA自学笔记,面向对象编程。_第4张图片
在这里插入图片描述
这里为了方便大家能看清,上面例子中int类型的x和y,也就是add方法后面括号里的就是形参,它的意思是这个方法需要传递两个int类型的值,其实主要的就是前面数据类型,后面的x和y可以用任何字母代替。main方法里面先使用Math创建了一个a对象,然后定义了两个变量i和j然后在输出语句中使用对象a调用了Math类中的add方法,add后面括号里传递的就是实参。第二个输出语句输出了i和j的值,从运行结果可以看出,形参并没有对实参造成任何影响,

那么有的时候我们给方法传递的并不是值参数,而是引用参数。如果在给方法传递值是,参数的类型是数组或者其他引用类型,那么在方法装对参数的修改会反映到原有的数组或者其他引用类型上,这种类型的方法参数,我们称之为引用参数。
JAVA自学笔记,面向对象编程。_第5张图片
JAVA自学笔记,面向对象编程。_第6张图片
声明方法时,如果有若干个想同类型的参数,可以定义为不定长参数,该类型的参数声明方法,我们来看一个小例子。

JAVA自学笔记,面向对象编程。_第7张图片
在这里插入图片描述
通过上面的小例子大家看出来什么没有?这里要特别注意一点,不定长参数必须是方法中的最后一个参数,任何其他常规参数必须在他前面。
下面再来一个小例子。
JAVA自学笔记,面向对象编程。_第8张图片
JAVA自学笔记,面向对象编程。_第9张图片
大家可以通过自己的想法去写一些小例子练练。一定要多写多练。

构造方法

在类中除了成员方法以外,还存在一种特殊类型的方法,那就是构造方法,构造方法是一个与类同名的方法,对象的创建就是通过构造方法完成的。每当类实例化一个对象时,类都会自动调用构造方法。构造方法的特点如下。
1,构造方法没有返回值,也不能定义为void。
2,构造方法的名称必须与类名一致。
3,构造方法的主要作用是完成对象的初始化工作,他能把定义对象的参数传给对象成员。语法如下。

class Book{
public Book(){//构造方法
}
}

public:构造方法修饰符。
Book:构造方法的名称。
在构造方法中可以为成员变量赋值,这样当实例化一个本类对象时,相应的成员变量也将被初始化,如果类中没有明确定义构造方法,则编译器会自动创建一个无参的默认构造方法。除此之外,在类中定义构造方法时,还可以为其添加一个或者多个参数,既有参构造方法。

class Book{
public Book( int args){//构造方法
}
}

这里的args代表构造方法的参数,可以是多个参数。
注意,如果在类中定义的构造方法都是有参构造方法时,编译器不会为类自动生成一个默认的无参构造方法,当试图调用无参构造方法实例化一个对象时,编译器会报错。所以只有在类中没有定义任何构造方法时,编译器才会在该类中自动创建一个不带参的构造方法。
构造方法除了可以用public修饰以外,还可以使用private修饰,即私有的构造方法,私有的构造方法无法使用new创建对象,这时需要使用静态方法生成类对象。
JAVA自学笔记,面向对象编程。_第10张图片
在这里插入图片描述

局部变量

如果在成员方法内定义一个变量,那么这个变量被称为局部变量。
局部变量在方法被执行时创建,在方法执行结束时被销毁。局部变量在使用时必须进行赋值操作,或被初始化,否则会出现编译错误。
JAVA自学笔记,面向对象编程。_第11张图片

局部变量的有效范围

可以将局部变量的有效范围称为变量的作用域,局部变量的有效范围从该变量声明开始到该变量的结束为止。在互相不嵌套的作用域中可以同时声明两个名称的类型相同的局部变量。
JAVA自学笔记,面向对象编程。_第12张图片
但是在相互嵌套的区域中不可以这样声明,比如for循环的嵌套,我们就需要声明两个变量名称不一样的变量。

对象的创建

在Java语言中通过new操作符来创建对象。前面在讲解构造方法时介绍过,每实例化一个对象就会自动调用一次构造方法,实质上这个过程就是创建对象的过程。准确的说,可以再Java语言中使用new操作符调用构造方法创建对象。语法如下。

Test test = new Test();
Test test = new Test("a");

Test:类名。
test:对象名。
new:创建对象操作符。
a:构造方法的参数。
test对象被创建出来时,就是一个对象的引用,这个引用在内存中为对象分配了储存空间,前面介绍过,可以再构造方法中初始化成员变量,当创建对象时,自动调用构造方法,也就是说在Java语言中初始化与创建是被捆绑在一起的。也就是对象在被创建出来的时候就完成了初始化。要注意,引用只是存放一个对象的内存地址,并非存放一个对象,严格地来说引用和对象时不同的,但是可以将这种区别忽略,可以简单的说test是Test类的一个对象,而事实上应该是test包含Test对象的一个引用。
没个对象都是相互独立的,在内存中占据独立的内存地址,并且没个对象都具有自己的生命周期,当一个对象的声明周期结束时,对象就变成垃圾,由Java虚拟机自带的垃圾回收机制处理,不能再被使用。

访问对象的属性和行为

用户使用new操作符创建一个对象后,可以使用“对象.类成员”来获取对象的属性和行为。前面说到过,对象的属性和行为在类中式通过类成员变量和成员方法的形式来表示的。所以当对象获取类成员时,也相应地获取了对象的属性和行为。我们来看一个例子。
JAVA自学笔记,面向对象编程。_第13张图片
JAVA自学笔记,面向对象编程。_第14张图片
在上面的代码的主方法中首先实例化一个对象,然后使用**“.”**操作符调用类的成员变量和成员方法,但是在运行结果中可以看到,虽然使用两个对象调用同一个成员变量,结果却不相同,因为在打印这个成员变量的值之前,将该值重新赋值为60,但是赋值时使用的是第二个对象t2调用成员变量,所以在第一个对象t1调用成员变量打印该值时忍让是成员变量的初始值。由此可见,两个对象的产生是相互独立的,改变了t2的i值,不会影响到t1的i值。

对象的销毁

没个对象都有声明周期,当对象的生命周期结束时,分配给该对象的内存地址会被回收。在其他语言中需要手动回收废弃的对象,但是Java拥有一套完整的垃圾回收机制,用户不必担心废弃的对象占用内存,垃圾回收器将回收无用的但占内存的资源。
在谈到垃圾回收机制之前,首先需要了解何种对象会被Java虚拟机视为垃圾,主要包括一下两种情况:
1,对象的引用超过其作用范围,这个对象将被视为垃圾。
2,将对象赋值为null(空值)。
虽然垃圾回收机制已经很完善,但垃圾回收器只能回收哪些由new操作符创建的对象,如果某些对象不是通过new操作符在内存中获取一块内存区域,这种对象可能不能被垃圾回收机制所识别,所以在Java中提供了一个finalize()方法。这个方法是Object类的方法,它被声明为protected,用户可以在自己的类中定义这个方法。如果用户在类中定义了finalize()方法,在垃圾回收是会首先调用该方法,在下一次垃圾回收动作发生时,才能真正回收被对象占用的内存。有一点需要明确的是,垃圾回收或finalize()方法不保证一定会发生,如Java虚拟机内存消耗殆尽时,它是不会执行垃圾回收的。
由于垃圾回收不受人为控制,具体执行时间也不确定,所以finalize()方法也就无法执行,为此,Java中提供了System.gc()方法强制启动垃圾回收器,这就好比打电话给120通知医院来救人。告知垃圾回收器进行清理。

this关键字

当类中的成员变量与成员方法中的参数重名时,方法中如何使用成员变量呢?下面来看一下重名的情况下会发生什么问题。
JAVA自学笔记,面向对象编程。_第15张图片
在这里插入图片描述
从这个结果可以看出,输出的值不是成员变量的值,也就是说如果方法中出现了与局部变量同名的参数,会导致方法无法直接使用该成员变量。在上面的代码中可以看到,成员变量与在showName()方法中的形参名称相同,都为name,Java中遵循就近原则,也就是说哪个name离他近他就用哪个name,很明显,形参的name离得近,所以控制台输出了123。那么该如何在类中区分使用的是哪一个变量呢?在Java语言中规定使用this关键字来代表本类对象的引用,this关键字被隐式的用于引用变量的成员变量和方法。我们给上面的例子做一些小小的修改。
JAVA自学笔记,面向对象编程。_第16张图片
在这里插入图片描述
既然this关键字和对象都可以调用成员变量和成员方法,那么this关键字与对象之间具有怎样的关系呢?
事实上,this引用的就是本类的一个对象,在局部变量或方法参数覆盖了成员变量时,就要添加this关键字明确引用的是类成员还是局部变量或方法参数。
如果省略this关键字直接写成name=name,那只是把参数name赋值给参数变量本身而已,成员变量name的值没有改变,因为参数name在方法的作用域中覆盖了成员变量name。
其实,this除了可以调用成员变量或成员方法之外,还可以作为方法的返回值。例如:

public class Book{
public Book getBook(){
return this;//返回book类引用
}
}

在getBook()方法中,方法返回的值为Book类,所以方法体中使用return this这种形式将Book类的对象进行返回。事实上this还可以调用类中的构造方法。比如买鸡蛋灌饼,我要求多加几个鸡蛋时,商家就多给几个鸡蛋,不要求时默认加一个鸡蛋。上例子。
JAVA自学笔记,面向对象编程。_第17张图片
在这里插入图片描述
在上面的代码中可以看到定义了两个构造方法,在无参构造方法中可以使用this关键字调用有参的构造方法。但是要注意,this()语句之前不可以有其他代码。

static关键字

由static修饰的变量,常量,和方法被称作静态变量,静态常量,和静态方法,也被称为类的静态成员。静态成员是属于类所有的,区别于个别对象。

静态变量

很多时候,不同的类之间需要对同一个变量进行操作,好比一个水池,同时打开入水口和出水口(作者吐槽:又是这种神经病做法),进水和出水这两个动作会同时影响到池中的水量,此时池中的水量就可以认为是一个共享的变量。在Java程序中,把共享的变量用static,该变量就是静态变量。可以在本类或其他类使用类名和“.”运算符调用静态变量。

类名.静态类成员

让我们来看看这个水池。
JAVA自学笔记,面向对象编程。_第18张图片
JAVA自学笔记,面向对象编程。_第19张图片
同一个类的不同实例对象,共用同一个静态变量,如果一个类将其更改,另一个类静态变量也会更改。
JAVA自学笔记,面向对象编程。_第20张图片
在这里插入图片描述
从结果我们发现s.x的值并不是我们赋予的初值,而是和s1.x的值一样。这是因为StaticVariable类的静态变量x是被本类共享的,当对象s给x赋值以后,s1又给x赋了一次值,最后x就变成了s1.x的字面值了。当类首次被加载时,静态变量就被分配到内存中,知道程序结束才会释放。

静态常量、

有时,在处理问题时会需要两个类共享一个数据常量。例如,在球类中使用的PI这个常量,可能除了本类需要这个常量之外,在另一个园类中也需要使用这个常量,这是没有必要在两个类中同时创建PI这个常量,因为这样系统会将这两个不在同一个类中的常量分配到不同的内存空间中,浪费了系统西苑。为了解决这个问题,可以将这个常量设置为静态的。用final static修饰一个成员变量,这个成员变量就会变成一个静态常量。例。
JAVA自学笔记,面向对象编程。_第21张图片
在这里插入图片描述
注意一点,给静态常量命名时所有字母都应该大写。

静态方法

如果想要使用类中的成员方法,需要先将这个类进行实例化,但有些时候不想,或者无法串讲类的对象时,还要调用类中的方法才能够完成业务逻辑,此时就可以使用静态方法。调用类的静态方法,无需创建类的对象。

类名.静态方法();

JAVA自学笔记,面向对象编程。_第22张图片
在这里插入图片描述

静态代码块

在类中除成员方法之外,用static修饰代码块区域可以称之为静态代码块。定义一块静态代码块,可以完成类的初始化操作,在类声明时就会运行。

public class StaticTest{
static{
	//此处编辑执行语句
}
}

JAVA自学笔记,面向对象编程。_第23张图片
JAVA自学笔记,面向对象编程。_第24张图片
由以上代码可以看出以下几点。
1,静态代码块由始至终只运行了一次。
2,非静态代码块,每次创建对象的时候,会在构造方法之前运行。所以在读取成员变量name时,只能获取到String类型的默认值null。
3,构造方法只有在使用new创建对象的时候才会运行。
4,成员方法只有在使用对象调用的时候才会运行。
5,因为name是static修饰的静态成员变量,在创建s2对象时将字符串“s2”赋值给了name,所以创建s3对象时,重新调用了类的非静态代码块,此时那么的值还没有被s3对象改变,于是就会输出“s2非静态代码块”。

类的主方法

主方法是类的入口点,它定义了程序从何处开始,主方法提供对程序流向的控制,Java编译器通过主方法来执行程序。

public static void main (String[] args){
  //方法体
}

可以看到主方法具体有一下特征。
1,主方法是静态的,所以如要直接在主方法中调用其他方法,则该方法必须也是静态的。
2,主方法没有返回值。
3,主方法的形参为数组。其中args[0]~args[n]分别代表程序的第一个参数到第n+1个参数,可以使用args.length获取参数的个数。

你可能感兴趣的:(java笔记,java)