JavaSE基础知识总结(一)

自己对于java的特点和优点的理解总结

1、它是一门面向对象的编程语言,它吸收了C++语言各种优点的同时去除了C++语言中令人难以理解的多继承、指针等概念。java语言极好地实现了面向对象的理论,是静态面向对象编程语言的代表。

2、它可以做到“一次编译 到处运行“,具有平台独立性。跨平台的是java程序而不是JVM,所以需要在不同平台下安装不同版本的JVM。实质上利用了不同系统上都有自己的一套JVM来将Class字节码 文件编译成当前系统所能识别出来的机器语言。(目前市面上虚拟化技术已经非常成熟,比如你通过 Docker 就很容易实现跨平台了。在我看来,Java 强大的生态才是

3、java提供了很多内置的类库,提供了垃圾回收器,将开发人员从内存的管理中解脱出来。

4、适合用于web开发。有优质的且主流的框架

5、支持多线程

JDK 和 JRE

JDK 是 Java Development Kit 缩写,它是功能齐全的 Java SDK。它拥有 JRE 所拥有的一切,还有编译器(javac)和工具(如 javadoc 和 jdb)。它能够创建和编译程序。

JRE 是 Java 运行时环境。它是运行已编译 Java 程序所需的所有内容的集合,包括 Java 虚拟机(JVM),Java 类库,java 命令和其他的一些基础构件。但是,它不能用于创建新程序。

如果你只是为了运行一下 Java 程序的话,那么你只需要安装 JRE 就可以了。如果你需要进行一些 Java 编程方面的工作,那么你就需要安装 JDK 了。但是,这不是绝对的。有时,即使您不打算在计算机上进行任何 Java 开发,仍然需要安装 JDK。例如,如果要使用 JSP 部署 Web 应用程序,那么从技术上讲,您只是在应用程序服务器中运行 Java 程序。那你为什么需要 JDK 呢?因为应用程序服务器会将 JSP 转换为 Java servlet,并且需要使用 JDK 来编译 servlet。

自己对于面向对象和面向过程的区别理解与认识

两者的主要区别在于解决问题的方式不同:

  • 面向过程把解决问题的过程拆成一个个方法,通过一个个方法的执行解决问题

  • 面向对象会先抽象出对象,然后用对象执行方法的方式解决问题

另外,面向对象开发的程序一般更易维护、易复用、易扩展。面向对象有三大特征

封装

封装是指把一个对象的状态信息(也就是属性)隐藏在对象内部,不允许外部对象直接访问对象的内部信息。但是可以提供一些可以被外界访问的方法来操作属性。就好像我们看不到挂在墙上的空调的内部的零件信息(也就是属性),但是可以通过遥控器(方法)来控制空调。如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。就好像如果没有空调遥控器,那么我们就无法操控空凋制冷,空调本身就没有意义了(当然现在还有很多其他方法 ,这里只是为了举例子)。

继承

不同类型的对象,相互之间经常有一定数量的共同点。例如,小明同学、小红同学、小李同学,都共享学生的特性(班级、学号等)。同时,每一个对象还定义了额外的特性使得他们与众不同。例如小明的数学比较好,小红的性格惹人喜爱;小李的力气比较大。继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承,可以快速地创建新的类,可以提高代码的重用,程序的可维护性,节省大量创建新类的时间 ,提高我们的开发效率。

关于继承如下 3 点请记住:

  1. 子类会拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有

  1. 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。

  1. 子类可以用自己的方式实现父类的方法。

多态

多态,表示一个对象具有多种的状态,具体表现为父类的引用指向子类的实例。三个条件:1.需要有继承关系2.需要有方法的重写3.需要有父类的引用指向子类。

多态的特点:

  • 对象类型和引用类型之间具有继承(类)/实现(接口)的关系;

  • 引用类型变量发出的方法调用的到底是哪个类中的方法,必须在程序运行期间才能确定;

  • 多态不能调用“只在子类存在但在父类不存在”的方法;

  • 如果子类重写了父类的方法,真正执行的是子类覆盖的方法,如果子类没有覆盖父类的方法,执行的是父类的方法。

介绍一下java访问修饰符

有四种:public、protected、default、private.

public:能被当前项目下所有的类访问

protected:可以被当前类和当前类所在包的其他类以及子类访问。

default:只能被当前类和当前类所在包的其他类(子类不可以)

private:只能被当前类的内部访问。

自己对于java基本数据类型和引用类型的认识

数据类型

java有八大基本数据类型:分别是整数型(byte/short/int/long)、浮点型(float、double)、字符类型(char)和布尔类型(boolean)。jvm有专门的区域存放基本数据类型的值,如栈、堆。 基本数据类型存放在栈中是一个常见的误区! 基本数据类型的成员变量如果没有被 static 修饰的话(不建议这么使用,应该要使用基本数据类型对应的包装类型),就存放在堆中。

需要注意的浮点数没有办法用二进制精确表示,因此存在精度丢失的风险。

不过,Java 提供了BigDecimal 来操作浮点数。BigDecimal 的实现利用到了 BigInteger (用来操作大整数), 所不同的是 BigDecimal 加入了小数位的概念。

这 8 种基本数据类型的默认值以及所占空间的大小如下:

基本类型

位数

字节

默认值

取值范围

byte

8

1

0

-128 ~ 127

short

16

2

0

-32768 ~ 32767

int

32

4

0

-2147483648 ~ 2147483647

long

64

8

0L

-9223372036854775808 ~ 9223372036854775807

char

16

2

'u0000'

0 ~ 65535

float

32

4

0f

1.4E-45 ~ 3.4028235E38

double

64

8

0d

4.9E-324 ~ 1.7976931348623157E308

boolean

1

false

true、false

对于 boolean,官方文档未明确定义,它依赖于 JVM 厂商的具体实现。逻辑上理解是占用 1 位,但是实际中会考虑计算机高效存储因素。

另外,Java 的每种基本类型所占存储空间的大小不会像其他大多数语言那样随机器硬件架构的变化而变化。这种所占存储空间大小的不变性是 Java 程序比用其他大多数语言编写的程序更具可移植性的原因之一(《Java 编程思想》2.2 节有提到)。

注意:

  1. Java 里使用 long 类型的数据一定要在数值后面加上 L,否则将作为整型解析。

  1. char a = 'h'char :单引号,String a = "hello" :双引号。

  1. 基本数据类型之间会有隐式转化。

这八种基本类型都有对应的包装类分别为:Byte、Short、Integer、Long、Float、Double、Character、Boolean

引用类型

引用类型包括数组、类、接口、还要null类型,所谓引用数据类型就是对一个对象的引用。(如String等)。引用类型传递的值是地址值,基本上都是在堆区。

接口与抽象类的区别

相同点:1、二者都不能实例化;2、都可以拥有抽象方法。

区别:1、关键字不同(abstract class和interface);2、属性上接口只能有常量,抽象类可以有静态变量、常量和成员变量;3、抽象类中的方法可以有普通方法,而接口只能有默认方法和静态方法(1.8前没有)4、抽象类的方法可以有构造方法,接口不可以有构造方法;5、一个接口可以继承多个父接口,同时可以实现多个父类;6、抽象方法在业务编程上更像一个模板,有自己的功能,同时也有优化补充的多种形式,而接口更像是一种规范和要求。(抽象更像是A is a B关系,而接口更关注的是功能,某个操作。 )

包装类型的缓存机制?

Java 基本数据类型的包装类型的大部分都用到了缓存机制来提升性能。

Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character 创建了数值在 [0,127] 范围的缓存数据,Boolean 直接返回 True or False。

如果超出对应范围仍然会去创建新的对象,缓存的范围区间的大小只是在性能和资源之间的权衡。

两种浮点数类型的包装类 Float,Double 并没有实现缓存机制。(所以声明的就是不同对象)

下面我们来看一下问题。下面的代码的输出结果是 true 还是 false 呢?

Integer i1 =40;
Integer i2 =newInteger(40);
System.out.println(i1==i2);//false

所有整型包装类对象之间值的比较,最好全部使用 equals 方法比较

自动装箱与拆箱原理是什么?

什么是自动拆装箱?

  • 装箱:将基本类型用它们对应的引用类型包装起来;

  • 拆箱:将包装类型转换为基本数据类型;

  • Integer i = 10 等价于 Integer i = Integer.valueOf(10)

  • int n = i 等价于 int n = i.intValue();

final与static关键字

final可以修饰类,方法,变量。修饰类,该类不能被继承,修饰方法,该方法不能被重写,修饰变量必须初始化,该变量如果是基本变量则值不能再更改,如果是引用类型则地址不能,但值可以。

static可以修饰除构造器以外的其他4种成员。静态方法只能访问用static修饰的成员。被修饰的成员不属于某个对象,而是直接属于这个类,可以用过这个类名.的方式来获取这个成员或者调用静态方法,不过需要注意的是,静态方法中可以调用静态成员但是不能够调用非静态成员,而非静态方法可以访问静态成员和方法。因为被static修饰的部分,会优先加载,这个时候普通成员可能还没有被加载,就被你调用了,这显然不合理。

谈谈对String的认识

String、StringBuffer、StringBuilder 的区别?

可变性

String 是不可变的,为什么?

我们知道被 final 关键字修饰的类不能被继承,修饰的方法不能被重写,修饰的变量是基本数据类型则值不能改变,修饰的变量是引用类型则不能再指向其他对象。因此,final 关键字修饰的数组保存字符串并不是 String 不可变的根本原因,因为这个数组保存的字符串是可变的(final 修饰引用类型变量的情况)。

String 真正不可变有下面几点原因:

  1. 保存字符串的数组被 final 修饰且为私有的,并且String 类没有提供/暴露修改这个字符串的方法。

  1. String 类被 final 修饰导致其不能被继承,进而避免了子类破坏 String 不可变。

StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串,不过没有使用 final 和 private 关键字修饰,最关键的是这个 AbstractStringBuilder 类还提供了很多修改字符串的方法比如 append 方法

线程安全性

String 中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。

性能

每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

对于三者使用的总结:

  1. 操作少量的数据: 适用 String

  1. 单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder

  1. 多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer

详细说说==与equals()的区别

== 比较基本数据类型时,比较的是两个数值是否相等; 比较引用类型是,比较的是对象的内存地址是否相等。 equals() 没有重写时,Object默认以==来实现,即比较两个对象的内存地址是否相等; 重写以后,按照对象的内容进行比较。(因为 Java 只有值传递,所以,对于 == 来说,不管是比较基本数据类型,还是引用数据类型的变量,其本质比较的都是值,只是引用类型变量存的值是对象的地址。)

equals() 不能用于判断基本数据类型的变量,只能用来判断两个对象是否相等。equals()方法存在于Object类中,而Object类是所有类的直接或间接父类,因此所有的类都有equals()方法。

equals() 方法存在两种使用情况:

  • 类没有重写 equals()方法 :通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象,使用的默认是 Object类equals()方法。

  • 类重写了 equals()方法 :一般我们都重写 equals()方法来比较两个对象中的属性是否相等;若它们的属性相等,则返回 true(即,认为这两个对象相等)。

String 中的 equals 方法是被重写过的,因为 Object 的 equals 方法是比较的对象的内存地址,而 String 的 equals 方法比较的是对象的值。

当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。

hashCode() 有什么用?

hashCode() 的作用是获取哈希码(int 整数),也称为散列码。这个哈希码的作用是确定该对象在哈希表中的索引位置。

hashCode()定义在 JDK 的 Object 类中,这就意味着 Java 中的任何类都包含有 hashCode() 函数。另外需要注意的是: Object 的 hashCode() 方法是本地方法,也就是用 C 语言或 C++ 实现的,该方法通常用来将对象的内存地址转换为整数之后返回。

散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)

那为什么两个对象有相同的 hashCode 值,它们也不一定是相等的?

因为 hashCode() 所使用的哈希算法也许刚好会让多个对象传回相同的哈希值。越糟糕的哈希算法越容易碰撞,但这也与数据值域分布的特性有关(所谓哈希碰撞也就是指的是不同的对象得到相同的 hashCode )。

总结下来就是 :

  • 如果两个对象的hashCode 值相等,那这两个对象不一定相等(哈希碰撞)。

  • 如果两个对象的hashCode 值相等并且equals()方法也返回 true,我们才认为这两个对象相等。

  • 如果两个对象的hashCode 值不相等,我们就可以直接认为这两个对象不相等。

总结

  • equals 方法判断两个对象是相等的,那这两个对象的 hashCode 值也要相等。

  • 两个对象有相同的 hashCode 值,他们也不一定是相等的(哈希碰撞)。

  • hashCode():获取哈希码,equals():比较两个对象是否相等。

  • 二者两个约定:如果两个对象相等,它们必须有相同的哈希码;若两个对象的哈希码相同,他们却不一定相等。也就是说,equals()比较两个对象相等时hashCode()一定相等,hashCode()相等的两个对象equqls()不一定相等。

  • 加分回答:由于hashCode()与equals()具有联动关系,equals()重写时,hashCode()进行重写,使得这两个方法始终满足相关的约定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值