Java基础总结二

抽象类和接口的区别

抽象类:
含有abstract修饰符的class即为抽象类,abstract 类不能创建实例对象。含有abstract方法的类必须定义为abstract class,abstract class类中的方法不必是抽象的。abstract class类中定义抽象方法必须在具体(Concrete)子类中实现,所以,不能有抽象构造方法或抽象静态方法。如果子类没有实现抽象父类中的所有抽象方法,那么子类也必须定义为abstract类型。

接口:
接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final。

语法区别:
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
4. 抽象类中的抽象方法的访问类型可以是public,protected类,默认类型,但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
5. 抽象类中可以包含静态方法,接口中不能包含静态方法
6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。
7. 一个类可以实现多个接口,但只能继承一个抽象类。
应用区别:
接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约。而抽象类在代码实现方面发挥作用,可以实现代码的重用

原文地址:https://blog.csdn.net/qq_41933748/article/details/82670072

Object类方法

(1) public boolean equals(java.lang.Object) 比较对象的地址值是否相等,如果子类重写,则比较对象的内容是否相等;,基本类型数据结构是没有equals方法的

(2)public native int hashCode() 获取哈希码 对象签名,返回对象的物理地址,常会和equlas方法同时重写,确保有相同的hashcode
注意: equals返回true hashcode不一定以相同,但是hashcode相同equals一定返回true

(3)public java.lang.String toString() 把数据转变成字符串 获取对象信息的方法,将对象的信息变为字符串返回,默认输出对象地址

(4)public final native java.lang.Class getClass() 获取类结构信息
此方法不可重写,要调用的话一般和getName()联合使用,如getClass().getName() ,主要在反射中使用

(5)protected void finalize() throws java.lang.Throwable 垃圾回收前执行的方法 释放资源的方法,一般很少主动使用
主要用于垃圾回收中:
方法用途:无论对象是如何创建的,垃圾回收器都会负责释放对象占据的所有内存。这就将对finalize()的需求限制到一种特殊情况,即通过某种创建对象的方式以外的方式为对象分配了存储空间。这种情况一般发生在使用“本地方法”的情况下,本地方法是一种在Java中调用非Java代码的方式。
垃圾回收注意的点:
1)对象可能不被垃圾回收。
只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放。
2)垃圾回收并不等于“析构”。
3)垃圾回收只与内存有关。
使用垃圾回收的唯一原因就是为了回收程序不再使用的内存。
(6)protected native Object clone() throws java.lang.CloneNotSupportedException 克隆方法 主要完成对象的浅copy,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException
注意: Java中除了8种基本类型传参数是值传递,其他的类对象传参数都是引用传递,我们有时候不希望在方法里将参数改变,这时就需要在类中复写clone方法(实现深复制)。

(7)public final void wait() throws java.lang.InterruptedException
多线程中等待功能

(8)public final native void notify() 多线程中唤醒功能

(9)public final native void notifyAll() 多线程中唤醒所有等待线程的功能

类加载过程

概述:
类加载生命周期
类加载生命周期
类加载时机:
加载(loading)阶段,java虚拟机规范中没有进行约束,但初始化阶段,java虚拟机严格规定了有且只有如下5种情况必须立即进行初始化(初始化前,必须经过加载、验证、准备阶段):
(1)使用new实例化对象时,读取和设置类的静态变量、静态非字面值常量(静态字面值常量除外)时,调用静态方法时。
(2)对内进行反射调用时。
(3)当初始化一个类时,如果父类没有进行初始化,需要先初始化父类。
(4)启动程序所使用的main方法所在类
(5)当使用1.7的动态语音支持时。
如上5种场景又被称为主动引用,除此之外的引用称为被动引用,被动引用有如下3种常见情况
1)通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。
2)定义对象数组和集合,不会触发该类的初始化
3)类A引用类B的static final常量不会导致类B初始化(注意静态常量必须是字面值常量,否则还是会触发B的初始化)
4)通过类名获取Class对象,不会触发类的初始化。如System.out.println(Person.class);
5)通过Class.forName加载指定类时,如果指定参数initialize为false时,也不会触发类初始化。
6)通过ClassLoader默认的loadClass方法,也不会触发初始化动作
注意:被动引用不会导致类初始化,但不代表类不会经历加载、验证、准备阶段。
类加载方式
类加载不是指类加载阶段,而是指整个类加载过程,即类加载阶段到初始化完成。
隐式加载
创建类对象 ;使用类的静态域;创建子类对象;使用子类的静态域
在JVM启动时,BootStrapLoader会加载一些JVM自身运行所需的class
在JVM启动时,ExtClassLoader会加载指定目录下一些特殊的class
在JVM启动时,AppClassLoader会加载classpath路径下的class,以及main函数所在的类的class文件
显示加载:
ClassLoader.loadClass(className),只加载和连接、不会进行初始化
Class.forName(String name, boolean initialize,ClassLoader loader); 使用loader进行加载和连接,根据参数initialize决定是否初始化。
注意: 主要是 双亲委派模型
加载阶段
加载阶段,虚拟机主要完成三件事情:
1)通过一个类的全限定名来获取定义此类的二进制字节流
2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
相对于类生命周期的其他阶段而言,加载阶段(准确地说,是加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,因为开发人员既可以使用系统提供的类加载器来完成加载,也可以自定义自己的类加载器来完成加载。
连接阶段
3.1 验证:确保被加载的类的正确性
确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
文件格式验证:验证字节流是否符合Class文件格式的规范,如:是否以模数0xCAFEBABE开头、主次版本号是否在当前虚拟机处理范围内等等。
元数据验证:对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言规范的要求;如:这个类是否有父类,是否实现了父类的抽象方法,是否重写了父类的final方法,是否继承了被final修饰的类等等。
字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的,如:操作数栈的数据类型与指令代码序列能配合工作,保证方法中的类型转换有效等等。
符号引用验证:确保解析动作能正确执行;如:通过符合引用能找到对应的类和方法,符号引用中类、属性、方法的访问性是否能被当前类访问等等。
验证阶段是非常重要的,但不是必须的。可以采用-Xverify:none参数来关闭大部分的类验证措施。
**3.2 准备:**为类的静态变量分配内存,并将其赋默认值
为类变量分配内存并设置类变量初始值,这些内存都将在方法区中分配。对于该阶段有以下几点需要注意:
只对static修饰的静态变量进行内存分配、赋默认值(如0、0L、null、false等)。
对final的静态字面值常量直接赋初值(赋初值不是赋默认值,如果不是字面值静态常量,那么会和静态变量一样赋默认值)。
3.3 解析:将常量池中的符号引用替换为直接引用(内存地址)的过程
符号引用就是一组符号来描述目标,可以是任何字面量。属于编译原理方面的概念如:包括类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。
直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。如指向方法区某个类的一个指针。
假设:一个类有一个静态变量,该静态变量是一个自定义的类型,那么经过解析后,该静态变量将是一个指针,指向该类在方法区的内存地址。 具体见后续文章。
初始化
定义静态变量时指定初始值。如 private static String x=“123”;
在静态代码块里为静态变量赋值。如 static{ x=“123”; }
只有对类的主动使用才会导致类的初始化
原文地址:
https://blog.csdn.net/zhaocuit/article/details/93038538

反射

概念: 反射就是把Java类中的各个成分映射成一个个的Java对象。即在运行状态中,对于任意一个类,都能够知道这个类的所以属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性。这种动态获取信息及动态调用对象方法的功能叫Java的反射机制。
反射机制的主要功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
获得class的三种方式:
1、通过对象调用 getClass() 方法来获取,通常应用在:比如你传过来一个 Object类型的对象,而我不知道你具体是什么类,用这种方法
Person p1 = new Person();
Class c1 = p1.getClass();

2、直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高// 这说明任何一个类都有一个隐含的静态成员变量 class
Class c2 = Person.class;

3、通过 Class 对象的 forName() 静态方法来获取,用的最多,// 但可能抛出 ClassNotFoundException 异常
Class c3 = Class.forName(“com.ys.reflex.Person”);
需要注意的是:一个类在 JVM 中只会有一个 Class 实例
实现反射机制:获得class对象->获取构造方法->生成当前类对象

异常

结构图:
在这里插入图片描述
将异常分为两类:Error 和 RuntimeException 以及他们的子类。javac在编译时,不会提示和发现这样的异常,不要求在程序处理这些异常。所以如果愿意,我们可以编写代码处理(使用try…catch…finally)这样的异常,也可以不处理。对于这些异常,我们应该修正代码,而不是去通过异常处理器处理 。这样的异常发生的原因多半是代码写的有问题。如除0错误ArithmeticException,错误的强制类型转换错误ClassCastException,数组索引越界ArrayIndexOutOfBoundsException,使用了空对象NullPointerException等等。
检查异常:除了Error 和 RuntimeException的其它异常。javac强制要求程序员为这样的异常做预备处理工作(使用try…catch…finally或者throws)。在方法中要么用try-catch语句捕获它并处理,要么用throws子句声明抛出它,否则编译不会通过。这样的异常一般是由程序的运行环境导致的。因为程序可能被运行在各种未知的环境下,而程序员无法干预用户如何使用他编写的程序,于是程序员就应该为这样的异常时刻准备着。如SQLException , IOException,ClassNotFoundException 等。
异常的处理方法:
1)try…catch…finally语句块

try{
     //try块中放可能发生异常的代码。
     //如果执行完try且不发生异常,则接着去执行finally块和finally后面的代码(如果有的话)。
     //如果发生异常,则尝试去匹配catch块。

}catch(SQLException SQLexception){
    //每一个catch块用于捕获并处理一个特定的异常,或者这异常类型的子类。Java7中可以将多个异常声明在一个catch中。
    //catch后面的括号定义了异常类型和异常参数。如果异常与之匹配且是最先匹配到的,则虚拟机将使用这个catch块来处理异常。
    //在catch块中可以使用这个块的异常参数来获取异常的相关信息。异常参数是这个catch块中的局部变量,其它块不能访问。
    //如果当前try块中发生的异常在后续的所有catch中都没捕获到,则先去执行finally,然后到这个函数的外部caller中去匹配异常处理器。
    //如果try中没有发生异常,则所有的catch块将被忽略。
}catch(Exception exception){
    //...
}finally{
       //finally块通常是可选的。   
       //无论异常是否发生,异常是否匹配被处理,finally都会执行。
       //一个try至少要有一个catch块,否则, 至少要有1个finally块。但是finally不是用来处理异常的,finally不会捕获异常。
      //finally主要做一些清理工作,如流的关闭,数据库连接的关闭等。 
}

注意:
1、try块中的局部变量和catch块中的局部变量(包括异常变量),以及finally中的局部变量,他们之间不可共享使用。
2、每一个catch块用于处理一个异常。异常匹配是按照catch块的顺序从上往下寻找的,只有第一个匹配的catch会得到执行。匹配时,不仅运行精确匹配,也支持父类匹配,因此,如果同一个try块下的多个catch异常类型有父子关系,应该将子类异常放在前面,父类异常放在后面,这样保证每个catch块都有存在的意义。
3、java中,异常处理的任务就是将执行控制流从异常发生的地方转移到能够处理这种异常的地方去。也就是说:当一个函数的某条语句发生异常时,这条语句的后面的语句不会再执行,它失去了焦点。执行流跳转到最近的匹配的异常处理catch代码块去执行,异常被处理完后,执行流会接着在“处理了这个异常的catch代码块”后面接着执行。
有的编程语言当异常被处理后,控制流会恢复到异常抛出点接着执行,这种策略叫做:resumption model of exception handling(恢复式异常处理模式 )而Java则是让执行流恢复到处理了异常的catch块后接着执行,这种策略叫做:termination model of exception handling(终结式异常处理模式)
throws 函数声明
throws声明:如果一个方法内部的代码会抛出检查异常(checked exception),而方法自己又没有完全处理掉,则javac保证你必须在方法的签名上使用throws关键字声明这些可能抛出的异常,否则编译不通过。
throws是另一种处理异常的方式,它不同于try…catch…finally,throws仅仅是将函数中可能出现的异常向调用者声明,而自己则不具体处理。
采取这种异常处理的原因可能是:方法本身不知道如何处理这样的异常,或者说让调用者处理更好,调用者需要为可能发生的异常负责。
finally块
finally块不管异常是否发生,只要对应的try执行了,则它一定也执行。 只有一种方法让finally块不执行:System.exit()。 因此finally块通常用来做资源释放操作:关闭文件,关闭数据库连接等等。
良好的编程习惯是:在try块中打开资源,在finally块中清理释放这些资源。
需要注意的地方:
1、finally块没有处理异常的能力。处理异常的只能是catch块。
2、在同一try…catch…finally块中 ,如果try中抛出异常,且有匹配的catch块,则先执行catch块,再执行finally块。如果没有catch块匹配,则先执行finally,然后去外面的调用者中寻找合适的catch块。
3、在同一try…catch…finally块中 ,try发生异常,且匹配的catch块中处理异常时也抛出异常,那么后面的finally也会执行:首先执行finally块,然后去外围调用者中寻找合适的catch块。
有关finally 的注意点:
1)finally中的return 会覆盖 try 或者catch中的返回值。
2)finally中的return会抑制(消灭)前面try或者catch块中的异常
3)finally中的异常会覆盖(消灭)前面try或者catch中的异常
原文地址:
https://www.cnblogs.com/lulipro/p/7504267.html

String类

从源码看出String底层使用一个字符数组来维护的。成员变量可以知道String类的值是final类型的,不能被改变的,所以只要一个值改变就会生成一个新的String类型对象,存储String数据也不一定从数组的第0个元素开始的,而是从offset所指的元素开始。
两种实例化字符串的区别:
1)直接赋值(String str = “hello”):只开辟一块堆内存空间,并且会自动入池,不会产生垃圾。
2)构造方法(String str= new String(“hello”);):会开辟两块堆内存空间,其中一块堆内存会变成垃圾被系统回收,而且不能够自动入池,需要通过public String intern();方法进行手工入池。
String常用方法
在这里插入图片描述
字符串的拼接操作:
注意事项:
1,常量与常量的拼接结果在常量池,原理是编译期优化,常量池中不会存在相同内容的变量。拼接的字符串中只要其中有一个是变量,结果就在堆中。
2,变量拼接的原理是StringBuilder,如果拼接的结果调用intern()方法,根据该字符串是否在常量池中存在,分为:
2.1 存在: 则返回字符串在常量池中的地址如果字符串常量池中
2.2 不存在: 则在常量池中创建一份,并返回此对象的地址
拼接过程:

 StringBuilder s = new StringBuilder();
     s.append(str);
     s.append("world");
     String str = s.toString();

通过StringBuilder的append()的方式添加字符串的效率要远高于使用String的字符串拼接方式!
原因1:StringBuilder的append()的方式:自始至终中只创建过一个StringBuilder的对象
原因2:使用String的字符串拼接方式:创建过多个StringBuilder和String(调的toString方法)的对象,内存占用更大;如果进行GC,需要花费额外的时间(在拼接的过程中产生的一些中间字符串可能永远也用不到,会产生大量垃圾字符串)
问题:string和stringbuffer和stringbuilder的区别?
String:适用于少量的字符串操作。
StringBuilder:适用于单线程下在字符串缓冲区进行大量操作。
StringBuffer:适用于多线程下在字符串缓冲区进行大量操作。
1)String是final类不能被继承且为字符串常量,而StringBuilder和StringBuffer均为字符串变量。在Java中字符串使用String类进行表示,但是String类表示字符串有一个最大的问题:“字符串常量一旦声明则不可改变,而字符串对象可以改变,但是改变的是其内存地址的指向。”所以String类不适合于频繁修改的字符串操作上,所以在这种情况下,往往可以使用StringBuffer类,即StringBuffer类方便用户进行内容修改。
2)在String类中使用“+”作为数据的连接操作,而在StringBuffer类中使用append()方法(方法定义:public StringBuffer append(数据类型 变量))进行数据连接。
3)类的定义不同
String类:

public final class String extends Object implements Serializable, Comparable<String>, CharSequence

StringBuffer类:

public final class StringBuffer extends Object implements Serializable,CharSequence

StringBuilder类:

public final class StringBuilder extends Object implements Serializable,CharSequence

4)String类和StringBuilder、StringBuffer类的转换。
1.String类通过apend()方法转换成StringBuilder和StringBuffer类。
2.StringBuffer类和StringBuilder类通过to.String()方法转换成String类型
5)String类、StringBuffer和StringBuilder类中定义的常用方法,三类的大部分方法(下例)可以互补。
6)线程安全性方面
1.StringBuilder(非线程安全)
该类提供一个与StringBuffer兼容的 API,但不能保证同步,所以在性能上较高。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。

2.StringBuffer(线程安全的)
StringBuffer上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。

ArrayList和LinkedList的区别

1、ArrayList和LinkedList可想从名字分析,它们一个是Array(动态数组)的数据结构,一个是Link(链表)的数据结构,此外,它们两个都是对List接口的实现。
前者是数组队列,相当于动态数组;后者为双向链表结构,也可当作堆栈、队列、双端队列

2、当随机访问List时(get和set操作),ArrayList比LinkedList的效率更高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。

3、当对数据进行增加和删除的操作时(add和remove操作),LinkedList比ArrayList的效率更高,因为ArrayList是数组,所以在其中进行增删操作时,会对操作点之后所有数据的下标索引造成影响,需要进行数据的移动。

4、从利用效率来看,ArrayList自由性较低,因为它需要手动的设置固定大小的容量,但是它的使用比较方便,只需要创建,然后添加数据,通过调用下标进行使用;而LinkedList自由性较高,能够动态的随数据量的变化而变化,但是它不便于使用。

5、ArrayList主要控件开销在于需要在lList列表预留一定空间;而LinkList主要控件开销在于需要存储结点信息以及结点指针信息。
原文地址:
http://blog.itpub.net/31543790/viewspace-2564119/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值