您的位置:首页 > 编程语言 > Java开发

Java基础_面向对象_类与对象、构造函数、关键字、静态代码块、单例

2013-09-11 09:15 253 查看

面向对象概念

相对面向过程而言,都是一种思想

面向过程强调的是功能行为

面向对象将功能封装进对象,强调具备了功能的对象

从执行者到指挥者

面试时结合实际场景描述面向对象

万物皆对象:你所接触到的,所想到的概念都可以是一个对象。面试不要说

写程序时不要先考虑功能,先面对对象。先找Java中是不是已经提供好了相对应的对象。没有对象,自己造一个对象,把功能定义到里面去

名词提炼法:把名词提炼出来封装成对象

面向对象三个特征:封装,继承,多态

以后开发:其实就是找对象使用,没有对象,就创建对象。

找对象,建立对象,使用对象。维护对象的关系

类与对象的关系

类:就是对像是生活中事物的描述

对象:就是这类事物实实在在存在的个体

类的描述:提取对象中共性内容,对具体的抽象

映射到java中,描述就是class定义的类。

具体对象就是对应java在堆内存中用new建立的实体,实体的成员变量都有默认初始化值。

定义类其实就是在描述事物的属性和行为,属性对应类中的变量,行为对应类中的函数(方法)

属性和行为共同称为类中的成员。属性称为成员变量,行为称为成员函数

Car c = new Car();//c就是一个类类型变量(引用星变量的一种)。记住:类类型变量指向对象

在java中指挥对象方式:对象.对象成员

对象的特点在于封装数据

成员变量和局部变量

作用范围:

成员变量作用于整个类中

局部变量作用于函数中,或者语句中

在内存中的位置:

成员变量在堆内存中,因为对象的存在才在内存中存在

局部变量存在于栈内存中,使用完就消失

匿名对象

是对象的简化形式,没有名字

new Car().run();

两种使用情况

1、当对对象方法仅进行一次调用的时候(因为调用方法匿名对象有意义,调用属性没有意义)。如果对多个成员调用,就必须给该对象取一个名字

2、匿名对象可以作为实际参数进行传递:show(new Car());写缓存的时候就会考虑到强引用,弱引用,软引用,定义对象的生命周期

封装

面向对象特性之一,是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。

透明的<==>隐藏的

好处:

将变化隔离
便于使用
提高重用性
提高安全性

封装原则:

将不需要对外提供的内容都隐藏起来
把属性都隐藏,提供公共方法

函数、类、包、框架都是封装体

private:

私有,权限修饰符中的一种,用于修饰类中的成员(成员变量、成员函数)。

私有只在本类中有效

将成员变量私有化以后,需要在类中提供访问该成员变量的方法(setAge()和getAge())

之所以对外提供访问方式,是因为可以在访问方法中加入逻辑判断语句,对访问的数据进行操作,提高代码的健壮性

私有仅仅是封装的一种表现形式

构造函数

特点:

1、函数名与类名相同

2、不用定义返回值类型,与void不同,注意区别

3、不可以写return语句

作用:

给对象进行初始化

注意:

1、默认构造函数的特点

2、多个构造函数是以重载的形式存在的

对象一建立,就会调用与之对应的构造函数

当一个类中没有定义构造函数时,系统会默认给该类加入一个空参数的构造函数:Person(){}

当在类中自定义了构造函数后,默认的构造函数就没有了

构造函数和一般函数的不同:

在写法上不同

在运行上不同。构造函数是在对象已建立就运行,给对象初始化

而一般方法是对象调用才执行,是给对象添加对象具备的功能

一个对象建立,构造函数只运行一次,而一般方法可以被对象调用多次

什么时候定义构造函数?

当分析事物时,该事物一存在就具备一些特性或者行为,那么将这些内容定义在构造函数中。

面试:构造代码块

作用:给对象进行初始化

对向一建立,就运行,而且优先于构造函数执行(先运行,不论构造代码块在构造函数前面还是后面)

和构造函数的区别:

构造代码块是给所有对象进行统一初始化,定义不同对象共性初始化内容。而构造函数是给对应的对象初始化

class Person

{

{//构造代码块

Sop("");

}

Person()//构造函数

{

...

}
}

构造函数可以私有化private

那么不能用该构造函数创建对象(单例设计模式)

this关键字

构造函数中局部变量的名称和成员变量的名称相同,用this标识成员变量,看上去是用于区分局部变量和成员变量重名的情况

this代表本类的对象,代表它所在函数所属对象的引用,简单说哪个对象在调用this所在的函数,this就代表那个对象

在类中被对象调用的成员,包括变量和函数

变量出现同名情况一定要加

类里面的成员被使用全是由对象完成的,而本类中的对象是this

this的应用

当定义类中功能时,该函数内部要用到调用该函数的对象时,这时用this来表示这个对象。但凡本类功能内部用到了本类对象都用this代表

构造函数间调用

this语句:用于构造函数之间互相调用,

只能定义在构造函数的第一行,因为初始化中的初始化要先执行,再执行自己的初始化,保证输出符合用户的输入。

Person(String name, int age)

{

this(name);//注意没有点,this代表对象

this.age = age;
}

不允许存在死循环的调用,示例如下:

Person()

{

this("haha");
}

Person(String name)

{

this();
}

static关键字

原因:

多个对象当中存在着共同数据,没有必要每一个对象都具备一个从而浪费内存空间

是一个修饰符,用于修饰成员(成员变量和成员函数)。不在堆内存当中,在方法区/共享区/数据区中

被修饰后的成员具备以下特点:

1、随着类的加载而加载,随着类的消失而消失,说明它的生命周期最长,非静态成员/实例变量则不是

String name;//成员/实例变量

static String country = "cn";//静态成员变量/类变量

2、优先于对象存在。

3、被所有对象所共享

4、除了可以被对象调用外,还可以直接被类名调用(类名.静态成员)

实例变量和类变量的区别:

1、存放位置。

类变量随着类的加载而存在于方法区中

实例变量随着对象的简历存在于对内存中

2、生命周期

类变量生命周期最长,随着类的消失而消失

实例变量生命周期随着对象的消失而消失

static使用注意事项:

静态方法只能访问静态成员,非静态方法既可以访问静态也可以访问非静态

静态方法中不可以写this,super关键字。因为静态优先于对象存在。

主函数是静态的

静态有利有弊

利:

对对象的共享数据进行单独空间的存储,节省空间。

可以直接被类名调用。

弊:

生命周期过长。

访问出现局限性。(静态虽好,只能访问静态)

主函数main

主函数是一个特殊的函数,作为程序的入口,可以被jvm调用

主函数的定义:

public:代表着该函数的访问权限最大

static:代表主函数随着类的加载就已经存在了。

void:主函数没有具体的返回值

main:不是关键字,但是是一个特殊的单词,可以被jvm识别。

(String[] arr): 函数的参数,参数类型是一个字符串类型的数组

主函数是固定格式的,包括参数格式,jvm可识别。虽然main可重载,但能被jvm识别的只有一种格式。只有args可以更改

jvm在调用主函数时传入的是new String[0];

主函数传值;

class MainDemo

{

public static void main(String[] args)

Sop(args[0]);
}

命令:java MainDemo haha hehe heihei

结果:haha

什么时候使用静态?

要从两方面考虑,因为静态修饰的内容有成员变量和成员函数

什么时候定义静态变量(类变量)?

当对象中出现共享数据时,该数据被静态所修饰

对象中的特有数据要定义成非静态存在于堆内存中

什么时候定义静态函数呢?

当功能内部没有访问到非静态数据(对象的特有数据),那么该功能可以定义成静态的。

例:

class Person

{

String name;

public static void show()

{

Sop("haha");

}
}

静态的应用--工具类

在工具类中的方法都定义成静态的,因为没有操作该类的特有数据。

将方法静态后,可以方便于使用,但是该类还是可以被其他程序建立对象的。为了更为严谨,强制让该类不能建立对象,可以通过将构造函数私有化完成

当一个类中用到了其他类,编译时该类文件时jvm先找当前目录下有无其他类的class文件,如果没有,则找有无java文件进行编译,最后才编译自己的java文件

帮助文档的制作javadoc

将工具类文件(ArrayTool.class)发送给他人,其他人只要将该文件设置到classpath路径下,就可以使用该工具类了

设置工具类的路径

set classpath = .;c:\myclass//加上点先找当前目录,再找指定目录

将A

但是该类中到底定义了多少个方法使用者不清楚,因为该类并没有使用说明书。

java的说明书通过文档注释完成

类的描述信息

/**

这是一个可以对数组进行操作的工具类,该类中提供了获取最值,排序等功能。

@author 张三

@version V1.1

*/

功能描述

凡是public修饰的功能都用文档注释描述,因为都可以被文档注释工具所提取

/**

获取一个整型数组中的最大值

@param arr 接受一个int类型的数组

@return 会返回一个该数组中的最大值

*/

javadoc -d 目录

javadoc -d myhelp -author -version ArrayTool.java//myhelp表示在当前目录下创建的文件夹名称(也可以指定路径)-author -version表示提取作者和版本

要将一个类生成帮助文档,该类必须是public修饰

只有两种权限才会被体现到注释文档中:public和protected,包括构造方法(如果需要对外提供给)

一个类中默认会有一个空参数的构造函数,这个函数的权限和所属类一致,如果类被public修饰,那么默认的构造函数也带public修饰符。

空参数构造函数不是默认构造函数,默认构造函数是看不见的

静态代码块

格式:

static

{

静态代码块中的执行语句;
}

特点:

随着类的加载而执行,只执行一次。优先于主函数

用于给类进行初始化

StaticCode s = null;//不会加载类,但凡用到了类中的内容了,才会加载类。

注意:构造代码块给该类的所有对象初始化,静态代码块给类初始化,构造函数给对应对象初始化

对象的初始化过程

Person p = new Person("zhangsan", 20);

1、因为new用到了Person.class文件,所以会先找到Person.class文件并加载到内存中

2、执行该类中的静态代码块,如果有的话,给Person.class类进行初始化

3、在堆内存中开辟空间,分配内存地址

4、在堆内存中建立对象的特有属性,并进行默认初始化

5、对属性进行显示初始化

6、对对象进行构造代码块初始化

7、对对象进行与之对应的构造函数初始化

8、将内存地址赋给栈内存中的P变量

单例设计模式

设计模式:解决某一类问题最行之有效的方法,java中有23种设计模式;

单例设计模式:解决一个类在内存中只存在一个对象

想要保证对象唯一

1,为了避免其他程序过多建立该类对象,先控制禁止其他程序建立该类对象

2,还为了让其他程序可以访问到该类对象,只好在本类中自定义一个对象

3,为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式

代码体现:

1、将构造函数私有化

2、在类中创建一个本类对象

3、提供一个方法可以获取到该对象

饿汉式

class Single

{

private Single(){}

private static final Single s = new Single();//类中的成员变量得私有化,final 使得s常量化,终身指向Single的实例

public static Single getInstance()//在外部不能通过对象访问,则只能铜鼓类名访问,所以方法是静态的

{

return s;

}
}

通过Single ss = Single.getInstance();//获取该对象

Single s1 = Single.getInstance();//main里面又多了一个变量s1,getInstance()方法还是返回的方法区中s的值,就保证了对象的唯一性

对于事物该怎么描述,还怎么描述,当需要将该事物的对象保证在内存中唯一时,就将以上的三步加上即可。(比如配置文件的数据封装在一个单例设计模式设计完的类当中)

上面的代码是先初始化对象。

称为饿汉式。

懒汉式

对象是方法被调用时才初始化,也叫做对象的延时加载,称为:懒汉式(有多线程问题,面试常考

class Single

{

private static Single s = null;//此处不能加final

private Single(){}

public static Single getInstance()

{

if(s==null)

s = new Single();

return s;

}
}

饿汉式和懒汉式的区别

饿汉式是Single类一加载进来,方法区里面就有s,堆里面就有对象,对象的地址值就赋给了s

懒汉式是Single类一加载s是空。当调用getInstance方法的时候,这个方法运行才在内存中建立对象,并把对象的内存地址值赋给s,才称为延时加载

懒汉式的缺点

cpu在某一时刻只能处理一个程序,如果多个人同时调用getInstance方法,在

if(s==null)

-->A程序停在此处

-->B程序停在此处

当A执行创建对象过后再执行B程序会创建多个对象

public static synchronized Single getInstance()//通过synchronized关键字上锁,A程序一进来其他程序就进不来了。因为每次都会判断锁,所以效率会变低,有判断。

最终解决方案

public static Single getInstance()

{

if(s==null)//此判断可以减少判断锁的次数,所以效率高

{

synchronized (Single.class)

{

if(s==null)//同步代码块加入判断的原因:如果第一个线程进入到第一个if代码块,此时并还没获取锁,此时虚拟机切换给第二个线程,它也进来了if代码块,并且此时获取锁,new一个对象,然后返回。接着虚拟机切换给第一个线程,它这时候才获取锁,此时如果没有第二个if判断,就会再new 一个对象,这就不能保证类的对象唯一性。也可以理解为在同步的外层加上if判断,来减少判断锁的次数。

s = new Single();

}

}

return s;
}

开发的时候用第一种饿汉式,安全,简单
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐