一、对于面向对象的理解
大学里面都学过c语言,c语言相对java来说是一种面向过程的语言,而java语言就是面向对象,面向对象时相对面向过程而言的,两者都是一种思想。
具体而言,面向过程更强调的是功能行为和过程,就是说实现某个功能的过程,;面向对象则是,把某个我们的功能封装进某个对象,这个对象具备某个我们可以调用的接口或者其他,我们只需要调用这个接口,来实现这个功能,而不必知道其具体过程是怎么实现的。
举个例子来说:
一个程序员,他会编程,公司需要他完成某个项目,公司不需要知道他具体怎么做,他怎么会的编程,只要完成公司项目就可以,这里公司调用了程序员的编程功能,公司就是一个指挥者,就是说我们是指挥者,只需调用我们需要的功能的对象即可,这就是面向对象。而程序员具体怎么完成任务,具体步骤和过程,这就是面向过程。
二、类和对象
1、类和对象的关系
两者描述:
1)类:就是对现实生活中事物的描述
2)对象:就是这类事物实在存在的个体
打个比方,比如一个建筑工程,类就是描述整个建筑工程的蓝图或者说图纸,上面关于尺寸,形状,功能都有具体的描述;对象就是依据这个图纸所建成的大楼,具有图纸上所有描述的功能和属性。相对应的,到java程序中,类就是class所定义的类,对象就是在java中通过new在堆内存中建立的实体。
描述来说比较抽象,比面向对象理解难一点,个人认为两者容易混淆,但认清两者使用方式和内存占用的话,就会区别的比较清楚。
使用方式来说:类中的属性和功能,不能直接通过类来调用(静态方法除外),只能通过建立对象来调用,就好比我们不能直接住进建筑的图纸里,但我们可以住进建好的建筑里。
内存占用来说:类,
2、对象的建立及调用
建立一个对象,格式为:类名 对象名称 = new 类名();
调用其中的属性和行为:对象名称.对象成员。
每new一个对象,就会在堆内存中建立一个对象。
示例程序:
class Person{
intage=20;
Stringname="zhangsan";
void study(){}
}
Person p =new Person();
p.age=24;
p.study();
3、匿名对象
就是没有名字的对象
有名字对象:Personp = new Person();
匿名对象: new Person();
匿名对象时对象的简化形式,只用在当对象方法仅进行一次调用的时候,而且匿名对象可以作为实际参数进行传递,这一点要注意,后面学习会用到很多。比如一个函数需要传递一个对象最为参数,这是就可以用匿名对象。
例子:new Car().color
new Car().color
new Car().run()
上面第一第二例子是建立了两个对象,当第二个对象建立的时候,第一对象已经变成垃圾了。而第三个对象,只调用了方法一次,这是可行的。
总而言之,匿名对象调用方式:当对象方法只调用一次时。如果对一个对象进行多个成员调用,就必须起名字了。
总结:使用方式:1、对象方法调用一次。2、作为参数
4、成员变量和局部变量区别
作用范围:成员变量作用与整个类中
局部变量作用与函数中和语句中
在内存中存储:成员变量在堆内存中(对象建立)
局部变量存在栈内存中
三、面向对象的三大个特征
三特征:封装,继承,多态
四、面向对象:封装
封装概念:是指隐藏对象的属性和实现细节,仅保留一个公共的对外访问方式。
优点:将变化隔离,便于使用,提高复用性和安全性
封装原则:将不需要对外提供给的内容都隐藏起来,把属性隐藏,仅提供公共方法对其进行访问。
1、封装
封装个人理解看来,就是对象的首个属性,我们将事物的属性和行为封装起来,这个对象可以实现某个功能,我们只是需要这个功能,像电视可是看节目,电脑可是显示文档,我们不需要知道其内部构造,只需一个开关点一下即可。这样,我们不用对其内部做什么改动,将变化隔离,同时提高了安全性,因为我们如果随便可以改动电视机里的电路,那么电视机就该坏了。这样我们就把具有某个工能的事物的内部封装到一个盒子里,不告诉你盒子内部有什么,也不让你操作,只给你提供一个方法,就是电视机那个按钮,这就是封装。函数就是java程序中最小的封装体。
封装后,调用方法或者使用功能就会变得简单了,我们只需要那个公共方法就可以得到我们需要的功能。
封装就得用到一个权限修饰符private:私有,这个权限修饰符可以修饰成员变量和成员方法,使得类中成员只被本类使用,只在本类中有效。本类之外是直接不知道这个类中有这个成变量和成员方法,只能调用public修饰的公共方法来进行这个功能的访问,不需要知道内部是怎么实现这个工能的过程,及其属性和行为。注意:私有,仅仅是封装的一种表现形式。
程序例子:
class Person{
private intage;
private String name;
void study(){}
}
现在类中age和name被私有化了,当我们在建立对象来调用age
Person p = new Person();
p.age=20;
这时就会报错,因为age被private修饰,不能访问。但我们需要设置或者获取这个age的值,所以对外提供公共方法:
public voidsetAge(int a){
age = a;
}
Public int getAge(){
return age;
}
通常,每个私有属性都会有两个公共访问方式,一个是设置,一个是获取。有公共访问方式,我们就可以对外面的访问数据进行筛选或者说判断,把我需要的数据传进来,这样提高了程序代码的健壮性。
2、构造函数
特点:函数名与类名一致,不用定义返回类型,不可以写return语句
作用:给对象进行初始化
注意:有默认的构造函数,多个构造函数以重载的形式存在
注意不定义返回类型和void的区别:void是一种返回值类型,代表没有具体返回值类型的情况,而构造函数是根本没有返回值类型。
构造函数示例:
class Person{
Person(){
执行语句
}
Person(int x){
执行语句
}
}
上述示例就是说,构造函数名必须是类名,而且构造函数不止一个,可以有多个,以重载的形式出现,每当我们执行一次 new Person();语句的时候,就是建立对象的时候,相应的构造函数就会被执行一次,就是对象建立即运行。这样表示,构造函数是给当前对象进行初始化的。之前,我们创建一个对象的时候,也没有构造函数,但是我们还是建立了,其实是系统默认给该类加入一个空参数的构造函数,比如上路例子如果我们不加构造函数,系统就会默认给我加一个空参数的构造函数Person(){}。当我自己定义的后,就没有这个系统默认的构造函数。
所以当我们自己写下构造函数,然后建立对象的时候没有使用相对应的构造函数,那么系统就会报错。构造函数也是可以私有化的,因为也属于类的成员,但是一旦私有化,我们建立对象使用这个构造函数的时候,就会出错。
总结来说,构造函数就是对象一建立就会调用的函数,与类同名,可以重载,用于给对象初始化,准确来说是给当前使用的构造函数创建的对象进行初始化。我们在分析事物的时候,当该事物具备一些建立的时就有的特性或行为,那没就可以将这些内容定义在构造函数中。
3、构造代码块
构造代码块,与构造函数类似,但又不同。
格式为
{
执行语句;
}
相对于构造函数来说,构造代码块就是“裸奔”,只有大括号包含的语句,作用也是给对象进行初始化。构造代码块和构造函数的区别:
相同之处:给对象进行初始化,都是对象一建立就运行
不同之处:1)构造代码块是给所有对象进行初始化,构造函数是给不同对象对象初始化。
2)构造代码块优先于构造函数执行
3)构造代码块是给不同对象的相同的共性初始化的,而构造函数是给不同对象进行个性的初始化的。
4、this关键字
先看示例:
class Person{
Stringname;
Person(String name){
this.name= name;
}
}
从程序上来看,我们传入的参数和类里的成员变量重名了,当没有this时候,name=name,就是自己给自己赋值,没有任何意义。此处,this就表示类里成员变量,从而就区分了局部变量和成员变量同名的情况。
this关键字:就代表本类的对象。可以说就是当前所调用的对象。
我们建立一个对象,对象里就会包含类中所描述的属性和行为,就像上述程序例子,我们一旦建立对象,就会有name和Person构造函数,当我们建立对象时,就会往里传一个name进行初始化,而这个构造函数被我们现在建立的这个对象所调用,所以,this就代表我们现在的这个对象。
总结的说,哪个对象在调用this所在的构造函数,this就代表哪个对象,且当定义类中功能时,该函数内部要用到本类对象时,就用this。
注意构造函数间调用:
类中如果我们在以个函数中调用相同类中的另一个函数,在函数中直接以函数名调用即可,在study函数中直接调用work函数,程序如下:
class Person{
intwork(){}
void study(){
work();
}
}
但构造函数间就不可以这样调用,需用到this关键字,在第二个构造函数中调用第一个构造函数:
class Person{
Person(intage){
执行语句
}
Person(int age,String name){
this(age);
}
}
为什么在第一行,因为初始化要先执行,如果初始化中还有初始化,那么先执行里面的初始化动作,就像上述的this调用构造函数。注意不要在两个构造函数见互相调用,会出现死循环。这种this语句只能用于构造函数之间。
5、static关键字
通常,对象在建立的时候有一些共有的数据,比如人,除了个人数据如年龄,姓名每个人都会不同,但都是中国人或者都是某一国籍的人。如果我们建立对象,那么每个对象里都会有一个中国国籍,而这个国籍我们可以把它提取出来作为共有数据来使用。这里就用到了static关键字。
static是一个修饰符,用于修饰成员变量和成员函数,注意,只能修饰成员,不能修士局部。示例程序:
class Person{
static String country = “China”;
}
这静态成员,可以直接被类名调用,调用方式为:类名.成员 如:Person.country
为什么可以有这些功能,这和内存有关:
之前我们学习过栈内存,堆内存,现在又有一个方法区或者是共享区、数据区。类中的共享数据和方法也在这里。
1) 静态修饰的成员,会在类的加载而加载,就是说类一加载,静态修饰的成员就会存到方法区中,也随着类的消失而消失。缺点也很明显,生命周期过长,占据方法去内存时间过长,所以不宜创建过多的静态成员。相对于对象来说,就优先于对象存在,也就优先于实例变量存在。
((小知识点:1、未被static修饰的成员变量,随着对象建立而存在于堆内存中,为实例变量。2、被static修饰的成员变量,因为随类的加载而加载,随类的消失而消失,存在于方法去中,称为类变量))。
2) 无法从非静态方法中引用非静态成员。因为静态优先于非静态存在,就是优先于对象存在,有静态的时候不一定有非静态,所以,静态方法只能访问静态成员。
非静态方法可以访问非静态成员也可以访问静态成员,因为内存中后出现,所以,两者都可以访问。
3) 静态方法中不可以使用this,super关键字,因为这两个字得先建立对象,所以不可。
4) 静态一点应用,如果建议一个工具类,其中没有特有数据,我们可以把方法都静态化,直接以类名进行调用即可,同时把构造函数私有化,这样就可避免不必要建立的对象。
总结:
什么时候使用静态:
1、定义静态变量:当对象中出现共享数据时,比如国籍,所属学校
2、定义静态函数:当功能内部没有访问到非静态数据(对象特有数据)时
6、静态的主函数
主函数是一个特殊的函数,是一个程序执行的起始点,是一个入口,可以被jvm识别并调用。
在主函数中,要注意main,这个不是关键字,但是是一个特殊的单词,可以被jvm识别。
(String[] args):函数参数,是一个数组类型,其中args可以再eclipse中设置程序初始参数args的信息。在dos命令行中,可以用java类名 数据1 数据2 数据… 来给主函数中的args传值。
尤其重要的一点,主函数格式是固定的,jvm识别
7、帮助文档制作,中注意,只有类名被public修饰的才可以使用文档注释。
8、静态代码块(小知识)
格式:static{
执行语句;
}
静态代码块特点:随着类的加载而加载,可以有多个静态代码块
静态代码块作用:给类进行初始化,并且由于主函数执行,且只执行一次。
既然是给类进行初始化,那么类一加载,静态代码块就会先执行。
小知识点:类的加载时间,如果有一下程序:Person p = null; 这时Person这个类是没有被加载进内存的,因为此处没有意义,没有用到一点类中的成员。而只要用到类中的成员,类才会被加载,像p=new Person(),Person.getAge(),这才会加载类。
总结:构造函数,构造代码块,静态代码块
|
初始化对象 |
执行次数 |
优先级 |
|
构造函数 |
对应对象(当前对象) |
同对象建立次数 |
最后 |
|
构造代码块 |
所有对象 |
同对象建立次数 |
次优 |
|
静态代码块 |
类 |
只执行一次 |
最优(随类加载) |
|
9、对象初始化过程
Person p = new Person(“zhangsan”,20);
这句话都做了什么?
1) 因为new用到了Person.class,所以会先找到Person.class文件加载到内存中
2) 执行该类中的static代码块,如果有的话,给Person.class类进行初始化
3) 在堆内存中开辟空间,分配内存地址值
4) 在堆内存中建立对象的特有属性,并进行默认初始化
5) 对属性进行显示初始化
6) 对对象进行构造代码块初始化
7) 对对象进行对应的构造函数的初始化
8) 将内存地址值赋给栈内存的p变量