面向对象三大特征
面向对象和面向过程
在平时的学习过程中,我们经常听到Java是面向对象的编程语言,C语言是面向过程的,那他们有什么区别呢?
- 面向对象: 所谓的面向对象,就是在编程的时候尽可能的去模拟真实的现实世界,按照现实世界中的逻辑去处理一个问题,分析问题中参与 其中的有哪些实体,这些实体应该有什么属性和方法,我们如何通过调用这些实体的属性和方法去解决问题。
优点:易维护、易复用、易扩展、面向对象有封装、继承、多态的特征,可以设计出低耦合的系统,使系统更加灵活、易于维护。
缺点:性能比面向过程差
- 面向过程:面向过程,就是按照我们分析好了的步骤,按部就班的依次执行就行了!所以当我们用面向过程的思想去编程或解决问题时,首先一定要把详细的实现过程弄清楚。一旦过程设计清楚,代码 的实现简直轻而易举。
优点:性能比面向对象好,因为类调用时需要实例化,开销比较大,比较浪费资源。
缺点:不易维护、不易复用、不易扩展
三大特征
封装性
封装性是面向对象编程的核心思想。指的就是将描述某种实体的数据和基于这些数的操作集合到一起,形成一个封装体。封装的思想保证了类内部数据结构的完整性,使用户无法轻易直接操作类的内部数据,这样降低了对内部数据的影响,提高了程序的安全性和可维护性。
继承性
面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
通过继承创建的新类称为“子类”或“派生类”。
被继承的类称为“基类”、“父类”或“超类”。
继承的过程,就是从一般到特殊的过程。
要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
多态性
多态其实就是同一个行为具有多个不同表现形式或形态的能力。将父类对象应用于子类对象的特征就是面向对象编程中的多态性的体现。
实现原理:
1.静态绑定即重载,重载是在一个类中,方法名相同,参数不同。返回值可以相同也可以不同,每个重载的方法都必须有一个独一无二的参数类型列表。
2.动态绑定即重写,重写是覆盖了原来的方法,实现不同的功能。一般用于子类在继承父类时,重写父类中的方法。它的原理是通过地址覆盖实现的。
实现条件:
1.继承:在多态中必须存在有继承关系的子类和父类。其中继承包括了接口的实现implements
2.方法重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
3.向上造型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
如果说面向对象是四个基本特征也没有错,抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。比如,我们要设计一个学生成绩管理系统,考察学生这个对象时,我们只关心他的班级、学号、成绩等,而不用去关心他的身高、体重这些信息。抽象包括两个方面,一是过程抽象,二是数据抽象。过程抽象是指任何一个明确定义功能的操作都可被使用者看作单个的实体看待,尽管这个操作实际上可能由一系列更低级的操作来完成。数据抽象定义了数据类型和施加于该类型对象上的操作,并限定了对象的值只能通过使用这些操作修改和观察。
类加载过程
装载
装载阶段的主要任务即生成当前类的class对象
装载阶段(也称加载阶段)是类加载的一个过程,这一阶段,虚拟机需要完成以下三件事情:
1)通过一个类的全限定名来获取定义此类的二进制字节流。
2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3)在Java堆中生成一个代表这个类的Java.lang.Class对象,作为方法区这些数据的访问入口。
链接
这一阶段又细分为三个阶段:
- 1.验证:进行魔数、JDK版本号数据验证,看是否符合虚拟机要求
- 2.准备:给静态变量开辟内存,并赋类型默认值
- 3.解析:这是将符号引用解析为直接引用的过程。
初始化
初始化阶段是给静态变量赋值的操作。
类初始化阶段是类加载过程的最后一步,前面的类加载过程中,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才开始真正执行类中定义的Java程序代码(或者说是字节码)。
条件
1.new 对象时
2.main函数类,因为main函数本身也是写在一个类中
3.类名.静态成员 ,即在调用静态方法或者静态变量时
4.反射,在我们获取当前类的class对象时
final关键字
1.修饰类:用filnal修饰的这个类不能有任何子类,一个类如果是final修饰的,那么其中所有的成员方法都无法进行覆盖重写(因为没有子类)
2.修饰方法:当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能被覆盖重写,对于类、方法来说。abstract关键字和final不能同时使用,因为矛盾
3.修饰变量:一旦使用final用来修饰变量,那么这个变量就不能进行更改,一次赋值,终生不变
Static关键字
首先,static关键字的基本作用,用一句话来描述就是:方便在没有创建对象的情况下来进行调用方法或变量。 static可以用来修饰类得成员方法、成员变量,以及代码块。
类的初始化顺序(这里可能笔试考的多):静态变量→静态块→实例变量→实例块→构造函数。
static用途
修饰变量
static变量也称作静态变量,静态变量和非静态变量的区别是:
1 、存储位置不同,实例变量存放在Java堆上,静态变量在方法区中
2、实例变量跟对象个数一一对象,它有多个副本,各个对象的副本互不影响。静态变量只跟类有关,一个类只有一份静态变量,在内存中只有一个副本。
3、他们的初始化顺序不同
修饰方法
static方法一般称为静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象。
静态方法和实例方法的区别:
1、在调用方式上:静态方法依赖于类,通过类 · 静态方法调用;实例方法依赖于类的对象,需要创建对象后,对象 · 实例方法使用。
2、使用上:实例方法内部不能定义静态变量,会编译出错;实例方法可以直接调用静态方法;静态方法无法直接调用实例方法(因为此时类还没有实例化)
3、内存分配:大家都以为“ 静态方法常驻内存,实例方法不是,所以静态方法效率高但占内存。”事实上,他们都是一样的,在加载时机和占用内存上,静态方法和实例方法是一样的,在类型第一次被使用时加载。调用的速度基本上没有差别。
修饰内部类
静态内部类通常称为嵌套类,它可以不依赖于外部类实例被实例化,与外围对象没有联系。而一般的内部类需要在外部类实例化后才能实例化。
内部类依靠外部类的存在为前提,而静态嵌套类则可以完全独立。
单例模式
所谓单例,就是整个程序有且仅有一个实例。该类负责创建自己的对象,同时确保只有一个对象被创建。在Java,一般常用在工具类的实现或创建对象需要消耗资源。
懒汉式
线程不安全,延迟初始化,严格意义上不是不是单例模式
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
饿汉模式
线程安全,比较常用,但容易产生垃圾,因为一开始就初始化
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
全局锁式
线程安全,线程同步时效率不高(synchronized)
public class Singleton{
private static Singleton singleton;
private Singleton(){}
//synchronized修饰的是静态方法,锁类对象
public synchronized static Singleton getInstance(){
if(singleton == null)
singleton = new Singleton();
return singleton;
}
}
静态代码块
线程安全,类主动加载时才初始化实例,实现了懒加载策略,且线程安全
public class Singleton {
private final static Singleton singleton;
private Singleton(){}
static {
singleton = new Singleton();
}
public static Singleton getInstance(){
//使用前将singleton属性通过静态代码块实现
return singleton;
}
public static void main(String[] args){
//第一次调用Singleton,JVM需要负责将其加载到内存中,在加载过程处理静态代码块
Singleton.getInstance();
//第二次调用Singleton,JVM中已经存在Singleton,直接使用getInstance
Singleton.getInstance();
}
}
双重锁模式
线程安全,延迟初始化。这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
双重检查模式,进行了两次的判断,第一次是为了避免不要的实例,第二次是为了进行同步,避免多线程问题。由于singleton=new Singleton()对象的创建在JVM中可能会进行重排序,在多线程访问下存在风险,使用volatile修饰signleton实例变量有效,解决该问题。
静态内部类(推荐)
线程安全,不存在线程同步问题,且单例对象在程序第一次getInstance()时主动加载SingletonHolder 和 静态成员INSTANCE
public class Singleton(){
private Singleton(){}
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInsatnce(){
return Singleton.SingletonHolder.INSTANCE
}
}