知识屋:更实用的电脑技术知识网站
所在位置:首页 > 科技

Java基础知识整理

发表时间:2022-03-25来源:网络

1. Java和C++的区别?

都是面向对象的语言,都支持封装、继承和多态Java 不提供指针来直接访问内存,程序内存更加安全Java 的类是单继承的,C++ 支持多重继承;虽然 Java 的类不可以多继承,但是接口可以多继承。Java 有自动内存管理机制,不需要程序员手动释放无用内存

 

2. Java和JavaSciprt的区别?

JavaScript 与 Java 是两个公司开发的不同的两个产品。Java 是原 Sun 公司推出的面向对象的程序设计语言,特别适合于互联网应用程序开发;而 JavaScript 是 Netscape 公司的产品,为了扩展 Netscape 浏览器的功能而开发的一种可以嵌入 Web 页面中运行的基于对象和事件驱动的解释性语言,它的前身是 LiveScript;而Java 的前身是Oak语言。

下面对两种语言间的异同作如下比较:

1)基于对象和面向对象:Java是一种真正的面向对象的语言,即使是开发简单的程序,必须设计对象;JavaScript是种脚本语言,它可以用来制作与网络无关的,与用户交互作用的复杂软件。它是一种基于对象(Object-Based)和事件驱动(Event-Driven)的编程语言。因而它本身提供了非常丰富的内部对象供设计人员使用;

2)解释和编译:Java 的源代码在执行之前,必须经过编译;JavaScript 是一种解释性编程语言,其源代码不需经过编译,由浏览器解释执行;

3)强类型变量和类型弱变量:Java采用强类型变量检查,即所有变量在编译之前必须作声明;JavaScript中变量声明,采用其弱类型。即变量在使用前不需作声明,而是解释器在运行时检查其数据类型;

4)代码格式不一样。

补充:其实Java和JavaScript最重要的区别是一个是静态语言,一个是动态语言。目前的编程语言的发展趋势是函数式语言和动态语言。在Java中类(class)是一等公民,而JavaScript中函数(function)是一等公民。

 

3. 简述JDK、JRE、JVM

1) JDK (Java Development Kit)

JDK 是整个JAVA的核心,包括了Java运行环境(Java Runtime Envirnment),一堆Java工具(javac/java/jdb等)和Java基础的类库(即Java API 包括rt.jar)。 

JDK是java开发工具包,它能够创建和编译程序。基本上每个学java的人都会先在机器 上装一个JDK。有这样一个关系,JDK包含JRE,而JRE包 含JVM。 

2) JRE(Java Runtime Environment)

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

3) JVM(Java Virtual Machine)

JVM 是运行 Java 字节码的虚拟机。JVM有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。字节码和不同系统的 JVM 实现是 Java 语言 “一次编译,随处可以运行” 的关键所在。

4)三者联系

我们利用JDK(调用JAVA API)开发JAVA程序后, 通过 JDK 中的编译程序(javac) 将我们的文本 java 文件编译成 java 字节码, 在JRE上运行这些 java 字节码, JVM 解析这些字节码, 映射到 CPU 指令集或 OS 的系统调用。

 

4. 面向对象和面向过程的区别

1) 面向过程 :面向过程性能比面向对象高。 因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发。但是,面向过程没有面向对象易维护、易复用、易扩展。
2) 面向对象 :面向对象易维护、易复用、易扩展。 因为面向对象有封装、继承、多态性的特性,所以可以设计出低耦合的系统,使系统更加灵活、更加易于维护。但是,面向对象性能比面向过程低。

 面向过程 :面向过程性能比面向对象高??

这个并不是根本原因,面向过程也需要分配内存,计算内存偏移量,Java性能差的主要原因并不是因为它是面向对象语言,而是Java是半编译语言,最终的执行代码并不是可以直接被CPU执行的二进制机械码。

而面向过程语言大多都是直接编译成机械码在电脑上执行,并且其它一些面向过程的脚本语言性能也并不一定比Java好。

 

5. 请说出八种基础数据类型及字节大小?

首先,字节即byte,位即bit;1 byte = 8 bit。

 类型包装类占用字节数据位取值范围1)整型byteByte1字节8(1*8)-128~127 shortShort2字节16(2*8)-32768~32767 int

Integer

4字节32(4*8)(-2的31次方 ~ 2的31次方-1) longLong8字节64位(-2的63次方 ~ 2的63次方-1)      2)浮点型floatFloat4字节32位float类型的数值有一个后缀F(例如:3.14F),没有后缀F的浮点数值(如3.14)默认为double类型 doubleDouble8字节64位       3)char型charCharacter2字节16位       4)boolean型booleanBoolean1字节8位false、true

每种包装类都有一个静态方法valueOf(),接受基本类型,返回引用类型;也都有一个实例方法xxxValue()返回对应的基本类型。

 

6. float型float f=3.4是否正确?

不正确;精度不准确,应该用强制类型转换:float f=(float)3.4 

 

7. short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?

short s1 = 1; s1 = s1 + 1;s1+1运算结果是int型,需要强制转换类型; 

short s1 = 1; s1 += 1;  可以正确编译,自动类型提升。

 

8. int 和 Integer 有什么区别

int 是基本数据类型,Integer 是引用数据类型;int 默认值是0,Integer 默认值是 null;int 类型直接存储数值,Integer 需要实例化对象,指向对象的地址。 public static void main(String[] args) { Integer a = new Integer(1); Integer b = new Integer(1); System.out.println(a == b); // false int c = 1; int d = 1; System.out.println(c == d); //true Integer e = 1; Integer f = 1; System.out.println(e == f); // true Integer g = 130; Integer h = 130; System.out.println(g == h); // false Integer i = new Integer(130); int j = 130; System.out.println(i == j); // true }

比较大小时,

都是封装类,都是 new 出来的,肯定不相等。因为对象的内存地址不一样。都是封装类,都不是 new 出来的,如果值在 -128~127 之间,那就相等,否则不相等。如果是封装类和基本类型进行比较,只要数值相等那就相等,否则就不相等。因为封装类和基本数据类型进行比较的时候会有一个自动拆箱操作。都是基本数据类型,如果数值相等,那就相等;否则不相等。

 

9. 8种基本类型的包装类和常量池

1)Java 基本类型的包装类的大部分都实现了常量池技术,即 Byte,Short,Integer,Long,Character,Boolean;这 5 种包装类默认创建了数值[-128,127] 的相应类型的缓存数据,但是超出此范围仍然会去创建新的对象。 为啥把缓存设置为[-128,127]区间?(参见issue/461)性能和资源之间的权衡。

2)两种浮点数类型的包装类 Float,Double 并没有实现常量池技术。

Integer i1 = 33; Integer i2 = 33; System.out.println(i1 == i2);// 输出 true Integer i11 = 333; Integer i22 = 333; System.out.println(i11 == i22);// 输出 false Double i3 = 1.2; Double i4 = 1.2; System.out.println(i3 == i4);// 输出 false

Integer 缓存源代码:

/** *此方法将始终缓存-128 到 127(包括端点)范围内的值,并可以缓存此范围之外的其他值。 */ public static Integer valueOf(int i) { if (i >= IntegerCache.low && i =-EPSINON) && (x=”或“非静态代码块—>构造方法)。 该类不管创建多少对象,静态代码块只执行一次.

3)静态内部类(static修饰类的话只能修饰内部类): 静态内部类与非静态内部类之间存在一个最大的区别: 非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类,但是静态内部类却没有。没有这个引用就意味着:①它的创建是不需要依赖外围类的创建。②它不能使用任何外围类的非static成员变量和方法。

4)静态导包(用来导入类中的静态资源,1.5之后的新特性):格式为:import static 。 这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名调用类中静态成员,可以直接使用类中静态成员变量和成员方法。

静态方法与非静态方法:

在外部调用静态方法时,可以使用 ”类名.方法名” 的方式,也可以使用 ”对象名.方法名” 的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。

static{}静态代码块 与 {}非静态代码块(构造代码块):

相同点: 都是在JVM加载类时且在构造方法执行之前执行,在类中都可以定义多个,定义多个时按定义的顺序执行,一般在代码块中对一些static变量进行赋值。不同点: 静态代码块在非静态代码块之前执行(静态代码块—非静态代码块—构造方法)。静态代码块只在第一次new执行一次,之后不再执行,而非静态代码块在每new一次就执行一次。 非静态代码块可在普通方法中定义(不过作用不大);而静态代码块不行。

 

32. this关键字

1)可以用来修饰属性、方法、构造器。

2)this理解为当前对象或当前正在创建的对象。比如:this.name,this.show();

3)可以在构造器中通过“this(形参)”的方式显示的调用本类中其它重载的指定的构造器。

要求:

在构造器内部必须声明在首行!若一个类中有n个构造器,那么最多有n-1个构造器中使用了this(形参);

 

33. super关键字

super可以用来修饰属性、方法、构造器

1)当子类与父类中有同名的属性时,可以通过"super.此属性"显式的调用父类中声明的属性。若想调用子类的同名的属性“this.此属性”。

2)当子类重写父类的方法以后,在子类中若想再显式的调用父类的被重写的方法,就需要使用“super.方法”

3)super修饰构造器:通过在子类中使用“super(形参列表)”来显式的调用父类中指定的构造器。

在构造器内部,“super(形参列表)”必须要声明在首行!        在构造器内部,“this(形参列表)”或“super(形参列表)”只能出现一个!当构造器中,不显式的调用“this(形参列表)”或“super(形参列表)”其中任何一个,默认调用的是父类空参的构造器!

建议:设计一个类时,尽量要提供一个空参的构造器!


 

34. 不能做switch()的参数类型是

在jdk 7 之前,switch 只能支持 byte、short、char、int 这几个基本数据类型和其对应的封装类型。switch后面的括号里面只能放int类型的值,但由于byte,short,char类型,它们会 自动 转换为int类型(精精度小的向大的转化),所以它们也支持。

注意,对于精度比int大的类型,比如long、float,doulble,不会自动转换为int,如果想使用,就必须强转为int,如(int)float;

jdk1.7后,整形,枚举类型,boolean,字符串都可以。

为什么jdk1.7后又可以用string类型作为switch参数呢?
其实,jdk1.7并没有新的指令来处理switch string,而是通过调用switch中string.hashCode,将string转换为int从而进行判断。

 

35. 请结合OO设计理念,谈谈访问修饰符public、private、protected、default在应用设计中的作用。

OO就是面向对象。那面向对象的四大特性就是:抽象 封装 继承 多态

从修饰符的角度来说,我觉得满足抽象和封装两个特性。一个类总有暴露给外面的方法,也有自己独立的方法不想被别人知道。修饰符的存在可以在包与包之间、类与类之间产生一种权限的关系,并不能保证随心所欲,这样才能确保安全。

权限从大到小排列:public、protected、缺省、private。

 

36. 引用与指针有什么区别?

指针和引用都是地址的概念,指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。

1)程序为指针变量分配内存区域,而不为引用分配内存区域。

2)指针使用时要在前加 * ,引用可以直接使用。

3)引用在定义时就被初始化,之后无法改变;指针可以发生改变。 即引用的对象不能改变,指针的对象可以改变。

4)没有空引用,但有空指针。这使得使用引用的代码效率比使用指针的更高。因为在使用引用之前不需要测试它的合法性。相反,指针则应该总是被测试,防止其为空。

5)对引用使用“sizeof”得到的是变量的大小,对指针使用“sizeof”得到的是变量的地址的大小。

6)理论上指针的级数没有限制,但引用只有一级。即不存在引用的引用,但可以有指针的指针。
int **p //合法
int &&p //非法

7)++引用与++指针的效果不一样。
例如就++操作而言,对引用的操作直接反应到所指向的对象,而不是改变指向;而对指针的操作,会使指针指向下一个对象,而不是改变所指对象的内容。

 

37. 虚函数和纯虚函数, 什么函数不能声明为虚函数?

推荐阅读:什么函数不能声明为虚函数

 

38. 如何实现不可变的类?

将类声明为final,所以它不能被继承将所有的成员声明为私有的,这样就不允许直接访问这些成员对变量不要提供setter方法将所有可变的成员声明为final,这样只能对它们赋值一次通过构造器初始化所有成员,进行深拷贝(deep copy)在getter方法中,不要直接返回对象本身,而是克隆对象,并返回对象的拷贝

推荐阅读:如何写一个不可变类?

 

39. 浅复制和深复制?怎样实现深复制?

浅度拷贝:复制一层对象的属性,并不包括对象里面的引用类型的数据,当改变拷贝的对象里面的引用类型时,源对象也会改变。·

深度拷贝:重新开辟一个内存空间,需要递归拷贝对象里的引用,直到子属性都为基本类型。两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。

 

收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜