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

面向对象概念

相对面向过程而言,都是一种思想
面向过程强调的是功能行为
面向对象将功能封装进对象,强调具备了功能的对象
从执行者到指挥者
面试时结合实际场景描述面向对象
万物皆对象:你所接触到的,所想到的概念都可以是一个对象。面试不要说
写程序时不要先考虑功能,先面对对象。先找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;
}
开发的时候用第一种饿汉式,安全,简单
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值