面向对象是相对于面向过程而言的,是现代软件设计的新思想:OOP
面向对象概念
理解面向对象
面向对象是相对面向过程而言
面向对象和面向过程都是一种思想
面向过程:强调的是功能行为
面向对象:将功能封装进对象,强调具备了功能的对象
面向对象是基于面向过程的
面向对象的特点
是一种符合人们思考习惯的思想
可以将复杂的事情简单化
将程序员从执行者转换成了指挥者
完成需求时:
- 先要去找具有所需的功能的对象来用
- 如果该对象不存在,那么创建一个具有所需功能的对象
- 这样简化开发并提高复用
面向对象开发,设计,特征
开发的过程:其实就是不断的创建对象,使用对象,指挥对象做事情
设计的过程:其实就是在管理和维护对象之间的关系
面向对象的特征:
封装
(encapsulation)继承
(inheritance)多态
(polymorphism)
类与对象的关系
- 使用计算机语言就是不断的在描述现实生活中 的事物
- java中描述事物通过类的形式体现,类是具体事 物的抽象,概念上的定义
- 对象即是该类事物实实在在存在的个体
类与对象(图例)
- 类就是图纸
- 汽车就是堆内存中的对象
对象内存结构
Car c1 = new Car();
c1.color="blue";
Car c2 = new Car();
匿名对象
匿名对象是对象的简化形式
匿名对象两种使用情况
- 当对对象方法仅进行一次调用的时
- 匿名对象可以作为实际参数进行传递
类的定义
Java作为面向对象的程序设计语言,其重要的一个概念就是类和对象。对象是类的实例,而类是对于对象的抽象提炼
- Java定义类的语法如下:
[修饰符] class 类名
{
零个到多个构造器定义···
零个到多个成员变量···
零个到多个方法···
}
- 注释:修饰符:
public
、final
、abstract
,类名:合法的标识符,每个单词首字母大写。static修饰的成员不能访问没有static修饰的成员 - 成员变量用于定义该类或该类实例所包含的状态数据,方法则用于定义该类或该类的实例的行为特征或者功能实现。
- 构造器是一个类创建对象的根本途径,如果没有构造器,那么这个类将无法创建实例。因此,如果一个类没有编写构造器,系统则会默认添加一个无参数无内容的构造器。如果编写了构造器,那么系统则不再添加
- 定义成员变量的语法格式如下:
[修饰符] 类型 成员变量名 [= 默认值 ];
注释:修饰符:修饰符可以省略,也可以是public、protected、private、static、final。public、protected、privat最多允许出现一个,可以和static、final组合。类型:Java中允许的任意数据类型。成员变量名:合法标识符即可,第一个单词首字母小写,后面的单词首字母大写。默认值:可以指定也可以不指定
- 定义方法的语法格式如下:
[修饰符] 方法返回值类型 方法名 ( 形参列表 )
{
//由零条到多条可执行语句组成的方法体
}
注释:修饰符:修饰符可以省略,也可以是public、protected、private、static、final、abstract。public、protected、privat最多允许出现一个,final、abstract最多可以出现一个,可以和static组合。方法返回值类型:Java中允许的任意数据类型,如果有返回值类型必须要有一个有效的return语句,且返回值类型必须与声明类型匹配。方法名:合法标识符即可,第一个单词首字母小写,后面的单词首字母大写。形参列表:定义该方法可以接受的参数
static说明:static可以修饰方法,成员变量。static修饰的成员表明它属于这个类本身,而不属于该类的单个实例,因此通常把static修饰的成员变量和方法也称之为类变量、类方法。不使用static修饰的普通方法、成员变量则属于该类的单个实例,而不属于该类。因为通常把不使用static修饰的成员变量和方法也称之为实例变量、实例方法。由static修饰的成员变量和方法称之为静态变量和静态方法,静态成员不能访问非静态成员
- 定义构造器的语法如下:
[修饰符] 构造器名 ( 形参列表 )
{
//由零条到多条可执行语句组成的构造器执行体
}
注释:修饰符:修饰符可以省略,也可以是public、protected、private其中之一。构造器名:必须与类名完全相同。形参列表:与定义方法形参列表的格式完全相同
对象的一些知识
对象的产生和使用
创建对象的根本途径是构造器,通过new关键字来调用某个类的构造器即可创建这个类的实例
Person person;
person = new Person();
等效于
Person person = new Person();
对象主要有以下作用:
- 访问对象的实例变量
- 调用对象的方法
变量和方法的访问方式:
类.类变量|方法
实例.实例变量|方法
注:static修饰的方法和成员变量既可以通过类也可以通过实例调用。
对象、引用和指针
在创建对象的时候会开辟对象变量所需的内存,而对象只是个引用,并不是实际存储变量的地方,其指向存储变量的实际地址也就是存放变量的堆(heap)内存中。而对象存在于栈内存中。其本质其实就是指针,不过是封装以后的指针。对象与对象之间的赋值也只是内存地址的赋值,并不是实际存储变量的赋值。
对象的this引用
this总是指向调用该方法的对象。根据this位置的不同,this作为对象的默认引用有两种情形。
- 构造器中引用该构造器正在初始化的对象
- 在方法中引用调用该类的对象
this关键字最大的作用就是让类中的一个方法,访问该类里的另一个方法或者实例变量
静态成员不能访问非静态成员的原因:对于static修饰的方法而言,则可以直接使用类来直接调用该方法,如果在static修饰的方法中使用this关键字,则这个关键字就无法指向合适的对象,所以static修饰的方法中不能使用this引用,由于static修饰的方法不能使用this引用,所以static修饰的方法不能访问不使用static修饰的普通成员,因此Java与法规定:静态成员不能访问非静态成员
this使用说明:大部分时候,普通方法、成员变量前面无需添加this,如果存在局部变量和成员变量同名,那么this不可省略。this还可以作为普通方法的返回值
方法详解
方法是类或者对象的行为特征的抽象,方法是类或对象最重要的组成部分。
-
方法的所属性
方法与函数的区别:方法由函数发展而来,但却有着显著不同,方法依附于类或者对象而存在。因此在定义方法的时候必须定义在类里面,而不能单独定义一个方法。如果有static修饰,那么这个方法属于这个类,否则属于这个类的实例。方法要执行,必须依附于类或对类的实例。 -
方法的参数传递机制
调用包含形参的方法时,必须传入相应的参数,实际传入的参数称之为实参。Java里方法的参数传递方式只有一种:值传递。值传递是将实际参数值的副本传入方法内,而参数本身不会受到任何影响。此处应该注意到基本数据类型传递就是本生数据的拷贝传递,因此在数据处理以后不会对当前数据造成影响,而引用类型的值传递,则是将引用类型的地址传了过去,此时指向的是同一个内存地址。 -
形参个数可变的方法
从JDK1.5以后,Java允许定义形参个数可变参数,从而允许为方法指定数量不确定的形参。在定义方法时,在最后一个形参的类型后面增加三个点(…)则表明该形参可以接受多个参数值,多个参数值当成数组传入。
e.g.
···
public static void test ( int a, String... books ){
for ( String tmp : books){
System.out.println(tmp);
}
}
···
-
递归方法
一个方法体内调用它自身,被称为方法递归。递归一定要向已知方向递归在遍历某个路径下的所有文件时候很有用。 -
方法重载
Java允许在同一个类里定义多个同名方法,只要形参列表不同就行。同一个类中,包含两个或以上的同名方法,但形参列表不同,则被称为方法重载。与返回值类型和修饰符等没有任何关系
成员变量和局部变量
-
成员变量是指在类里定义的变量(field)。
类变量(以static修饰):伴随着类的存在而存在
实例变量(不以static修饰):伴随着实例的存在而存在 -
局部变量是指在方法中定义的变量。
形参:定义方法时候定义的变量
方法局部变量:在方法体内部定义的局部变量,必须显式初始化
代码块局部变量:在代码块中定义的局部变量,必须显式初始化 -
成员变量的初始化和内存中的运行机制
当系统加载类或创建该类的实例时,系统自动为成员变量分配内存空间,并在分配内存空间后,自动为成员变量指定初始值 -
局部变量的初始化和内存中的运行机制
局部变量定义后,必须经过显式初始化后才能够使用,系统不会为局部变量执行初始化。只有在为这个变量赋值时候才会分配内存。局部变量属于方法,不属于类或实例。局部变量的作用域从初始化该变量开始,该方法或代码块运行结束而结束。(只保存基本数据类型的值或者对象的引用,所以所占内存小) -
变量的使用规则
尽可能的提高程序的内聚性
隐藏和封装
- 面向对象三大特征之一,指将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法实现对内部信息的操作和访问。
- 使用访问控制符
好处:
- 将变化隔离
- 便于使用
- 提高重用性
- 提高安全性
封装原则:
- 将不需要对外提供的内容都隐藏起来
- 把属性都隐藏,提供公共方法对其访问
private | default | protected | public | |
---|---|---|---|---|
同一个类中 | √ | √ | √ | √ |
同一个包中 | √ | √ | √ | |
子类中 | √ | √ | ||
全局范围内 | √ |
- package、import和import static
- 指定包名的格式(应放在第一个非注释行,一个类只能包含一个package语句):
package packageName;
- 指定生成类的位置就需要用
-d
参数指定,e.g.:javac -d . *.java
,此时生成的类将位于当前目录下指定的类包下,此时要执行类,则必须使用java packageName.*
- java的包机制需要两个方面的保证:①源文件使用package指定包名;②class文件必须放在相应的路径下。
- import可以向某个Java文件中导入指定包层次下的某个类或全部类,位于package以后,类定义以前。定义格式为:
import package.subpackage···ClassName;
- 导入某个包下的全部类
import package.sunpackage···.*;
- import static 用于导入静态成员变量和方法
Java源文件的大体结构:import static package.subpackage···.ClassName.fileName | methodName;
package 语句 //0个或1个 import | import static 语句 //0个或多个 public classDefinition | interfaceDefinition | enumDefinition //0个或1个public定义的 classDefinition | interfaceDefinition | enumDefinition //0个或多个普通的
- Java的常用包
java.lang
:包含Java语言的核心类,系统自动导入 -> String,Math,System,Thread等java.util
:包含大量的工具类/接口和集合框架/接口 -> Arrays,List,Set等java.net
:包含Java网络编程相关类/接口java.io
:包含Java输入/输出编程相关的类/接口java.text
:包含Java格式化相关的类java.sql
:包含Java进行JDBC数据库编程相关类/接口java.awt
:包含抽象窗口工具集的相关类/接口java.swing
:包含Swing图形用户编程的相关类/接口
构造函数
构造器是一个特殊方法,用于创建实例时执行初始化
- 在创建对象时,系统将为实例变量进行默认初始化,基本数据类型设为0或false,引用数据类型设置为null。若要改变这种数值,则在构造器中赋值。无论何时,Java类至少包含一个构造器。一旦自定义了构造器,系统将不再添加构造器。一般将构造器的权限设置为public,若只由其子类调用,则设置为protected,若不被允许创建实例,则设置为private
- 构造器作为一个特殊的方法,其本身也可以重载。这也方便了不同实例初始化值不相同的需求实现。如果重载过程有重复代码出现,则可以用this关键字来调用构造器方法
特点:
- 函数名与类名相同
- 不用定义返回值类型
- 不可以写return语句
作用:给对象进行初始化,在对象创建时候就调用
注意:
- 默认构造函数的特点
- 多个构造函数是以重载的形式存在的
Car car = new Car(); //此时Car()就是构造函数
当类中没有构造函数,那么编译器会添加无参且为空语句的构造函数
当类中存在构造函数,那么编译器不会添加构造函数
默认构造函数与类的权限保持一致
构造代码块
作用:给对象进行初始化
对象一建立就运行,而且优先于构造函数执行
和构造函数的区别:
- 构造代码块是给所有对象进行统一初始化,而构造函数是给对应的对象初始化
- 构造代码快中定义的是不同对象共性的初始化内容
this关键字
特点:this代表其所在函数所属对象的引用
换言之:this代本类对象的引用
什么时候使用this关键字呢?
当在函数内需要用到调用该函数的对象时,就用this
class Person
{
private String name;
Person(String name)
{
this.name = name;
}
}
this的应用:
- 当定义类中功能时,该函数内部要用到调用该函数的对象时,这时用this来表示这个对象,但凡本类功能内部使用了了本类对象,都用this表示
- 在构造函数中调用另一个构造函数
- this语句只能定义在构造函数的第一行。因为初始化要先执行
class Person{
private String name;
private int age;
Person(){
System.out.println("person run");
}
Person(String name){
this();
this.name = name;
}
Person(String name,int age){
this(name);
this.age = age;
}
}
static关键字
static关键字:用于修饰成员(成员变量和成员函数)
static关键字修饰的成员就是类成员。包括类变量,类方法,静态初始化块
- 类成员属于整个类,而不属于单个对象
- 类初始化时候为类变量分配内存空间,类初始化完成,类变量也初始化完成
- 系统创建类对象的时候,类变量不再分配内存
- 证明实例访问类方法实际上是类访问类方法的例子如下,其中test()是类方法
ClassName nas = null;
nas.test();
- 类成员不能访问实例成员的其中一个重要原因是因为类成员的作用域更大,可能出现类成员初始化完成,而实例成员还未初始化的情况,此时将出现错误
- 单例类(Singleton):始终只能创建一个实例的类
- 为了实现单例类:
①使用private修饰构造器方法
②提供一个public方法,且用static修饰。
③缓存已创建的对象(使用一个static修饰的成员变量来保存曾经创建的对象)。
class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if ( instance == null ){
instance = new Singleton();
}
return instance;
}
}
public class SingletonTest{
public static void main ( String[] args ){
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);
}
}
当成员被静态修饰后,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调用。类名.静态成员
实例变量和类变量的区别:
- 存放位置。
类变量随着类的加载而存在于方法区中
实例变量随着对象的建立而存在于堆内存中 - 生命周期:
类变量生命周期最长,随着类的消失而消失
实例变量生命周期随着对象的消失而消失
静态使用注意事项:
- 静态方法只能访问静态成员
非静态方法既可以访问静态也可以访问非静态 - 静态方法中不可以定义this,super关键字
因为静态优先于对象存在。所以静态方法中不可以出现this - 主函数是静态的
静态有利有弊
利处:对对象的共享数据进行单独空间的存储,节省空间。没有必要每一个对象中都存储一份。可以直接被类名调用
弊端:生命周期过长。访问出现局限性(只能访问静态)
被修饰后的成员具备以下特点:
- 随着类的加载而加载
- 优先于对象存在
- 被所有对象所共享
- 可以直接被类名调用
使用注意
- 静态方法只能访问静态成员
- 静态方法中不可以写this,super关键字
- 主函数是静态的
静态变量
当对象中出现共享数据时,该数据被静态所修饰
对象中的特有数据要定义成非静态存在于堆内存中
静态方法
当功能内部没有访问到非静态数据(对象的特有数据)
那么该功能可以定义成静态的
static常用于封装工具类,此时为了结构更严谨,将构造函数私有化
初始化块
初始化块和构造器的作用类似,都是对Java对象进行初始化操作。属于Java类里面的第四种成员。先定义的初始化块先执行,后定义的初始化块后执行
- 初始化代码块的语法格式如下:
[ 修饰符 ] {
//初始化代码块可执行代码
}
- 初始化代码块的修饰符只能是static,使用static修饰的初始化代码块被称之为静态初始化块,也称作类初始化块。静态初始化块总是先于普通初始化块执行
- 初始化块只是在创建Java对象时隐式执行,而且在执行构造器之前执行
- 从某种程度上来说,初始化代码块是构造器的补充,总是在构造器之前执行。初始化块不需要参数,因此可以讲不需要参数的初始化处理代码放入初始化块。尤其是不同构造器的初始化代码有重复的时候。其本质是从构造器中提取出来,在编译以后会被还原到构造器中,且位于构造器中的所有代码前面
- 当一个类初始化完成后,该类在虚拟机中便一直存在,第二次创建该类实例的时候无须再次对该类进行初始化