JAVA概念

Java语言有哪些特点:

1.三大特性(封装,继承,多态)

2.编译与解释共存

3.支持多线程(C++11开始,引用了多线程库)

4支持网络编程

JVM,JDK,JRE

JVM(java虚拟机)是运行java字节码的虚拟机,Windows,Linux,macOS都有各自的JVM,目的是为了能够在不同系统上使用相同的字节码,再不同的系统上得到一样的结果。(所以JVM是一次编写,随处运行的关键)。

JDK和JRE

JDK,它包含了JRE,它是JAVA的开发工具包,用来创建和编译程序(含有编译器javac)。

JRE是JAVA的运行环境,包含java虚拟机(JVM),java类库,java命令。

Java程序从源代码到运行的过程:

 首先写了一个java项目,通过javac编译为.class的java字节码文件,然后通过解释器,逐行解释,执行效率较慢,所以就引用了JIT(编译器),当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认定为 热点代码。为了提高热点代码的执行效率,在运行时虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化。

在HotSpot虚拟机中内置了两个即时编译器,一个是C1编译器,一个是C2编译器。

C1编译器主要关注点在于局部的优化,适用于执行时间较短或对启动性能有要求的程序,开启时间早,启动后不久就开始运行。

C2编译器为长期运行的服务器端进行调优,适用于执行时间长或对峰值性能有要求的程序,运行时间较晚,会等程序运行一段时间后才开始编译。

判断一段代码是不是热点代码,是不是需要出发即时编译,这样的行为称为热点探测,主要的热点探测判定方式有两种,分别如下:

1.基于采样的热点探测:

虚拟机会周期性的检查各个线程的栈顶,经常出现在栈顶的方法就是热点方法。(优点:高效,缺点:很难精确一个方法的热度)

2.基于计数器的热点探测:虚拟机会为每个方法定义一个计数器,统计执行的次数,超过一定阙值,就是热点方法。(优点:精确,缺点:低效)

JDK9引入了一种新的编译模式AOT,直接将字节码编译成机器码,避免了JIT预热等各方面的开销,JDK支持分层编译和AOT协作使用。

为什么不全使用AOT呢?

这和java语言的动态特性有关系,CGLIB动态代理使用的是ASM技术,而这种技术大致原理是直接在内存中生成并加载修改后的字节码文件也就是.class文件,如果全部使用AOT提前编译,就不能使用ASM技术了。为了支持类似的动态特性,所以选择JIT即时编译器。

为什么说JAVA语言"编译与解释共存"?

编译型:C++,执行速度快,开发效率低。

解释型:Pyhthon,PHP:执行速度慢,开发效率快。

Java 语言既具有编译型语言的特征,也具有解释型语言的特征。因为 Java 程序要经过先编译,后解释两个步骤,由 Java 编写的程序需要先经过编译步骤,生成字节码(.class 文件),这种字节码必须由 Java 解释器来解释执行。 

JAVA与C++的区别

1.java不提供指针来直接访问内存,程序内存更安全

2.java的类是单继承,C++支持多继承

3.java有自动内存管理垃圾回收机制(GC)

4.C++同时支持方法重载和操作符重载,但是Java只支持方法重载

continue,break和return的区别是什么?

1.continue:指跳出当前的这一次循环,继续下一次循环。

2.break:指跳出整个循环体,继续执行下面的语句。

3.return:用于跳出所在的方法,结束该方法的运行。(return一般有两种用法)

(1) return;直接使用return结束方法执行,用于没有返回值参数的方法

(2) return value;return一个特定值,用于有返回值参数的方法

 变量

语法形式:成员变量是属于类的,而局部变量是属于代码块或方法中定义的变量或是方法的参数;成员变量可被public,static,private修饰符修饰,而局部变量不能被访问修饰符和static修饰,但是成员变量和局部变量都能被final修饰。

存储方式:如果成员变量被static修饰,则该成员变量是属于类的,如果没有被static修饰,这个成员变量是属于实例的。对象存在于堆内存,局部变量存在于栈内存。

生存时间:成员变量是对象的一部分,它随着对象的创建而存在,局部变量是随着方法的调用而存在,方法的调用结束而消亡。

默认值:成员变量如果没有被赋初始值,则会自动以类型的默认值而赋值(被final修饰的成员变量必须赋值),而局部变量则不会自动赋值。

静态变量有什么作用

静态变量可以被类的所有实例共享。无论一个类创建了多少对象,它们都共享同一份静态变量。

static修饰的成员变量和成员方法习惯上称为静态变量和静态方法,可以直接通过类名来访问,访问语法为:

类名.静态方法名(参数列表…)

类名.静态变量名

字符型常量和字符串常量的区别?

1.形式:字符常量常是一个字符,字符串常量是0和若干个字符

2.含义:字符常量相当于一个整型值(ASCII值),可以参与运算;字符串常量代表一个地址值

3.占内存大小:字符占2个字节,字符串常量占若干个字节。

静态方法为什么不能调用非静态成员

静态方法是属于类的,在类加载的时候就会分配内存,通过类名直接访问。成员变量是属于实例的,只有再实例化之后才存在,需要通过类的实例对象去访问。非静态成员变量不存在的时候,静态成员变量就已经存在了,所以无法调用不存在的非静态成员变量。

静态方法和实例方法有何不同

1.调用方式不同

静态方法可以通过类名.方法名和对象.方法名调用,而实例方法只能采用后者。

2.访问类成员是否存在限制

静态方法只能访问静态成员,不允许访问实例成员,而实例方法不存在这个限制

重载和重写的区别

重载是根据输入数据的不同,采取不同的处理

重写,当子类继承父类的相同方法,输入数据一样时,采取与父类不一样的操作,覆盖父类的方法。

重载

发生于同一类中,方法名必须相同,参数类型,顺序,个数不同,返回类型和访问修饰符可以不同。

(重载就是同一个类中多个同名方法根据不同的传参来执行不同的逻辑处理。)

重写

重写发生在运行期,是子类对父类的允许访问的方法的实现过程进行重新编写。

1.方法名、参数列表必须相同,子类方法返回值类型应比父类方法返回值类型更小或相等,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类。

2.如果父类方法访问修饰符为 private/final/static 则子类就不能重写该方法,但是被 static 修饰的方法能够被再次声明。

3.构造方法无法被重写

如果方法的返回类型是 void 和基本数据类型,则返回值重写时不可修改。但是如果方法的返回值是引用类型,重写时是可以返回该引用类型的子类的。

什么是可变长参数

public static void method1(String... args) {
   //......
}

另外,可变参数只能作为函数的最后一个参数,但其前面可以有也可以没有任何其他参数。

public static void method2(String arg1, String... args) {
   //......
}

基本类型和包装类型的区别?

成员变量包装类不赋值就是null,而基本类型有默认类型。

包装类可以用于泛型,而基本类型不可以。

基本数据类型局部变量存放再Java虚拟机栈中的局部变量表中,基本数据类型的成员变量(未被static修饰)存放在Java虚拟机堆中。

包装类型属于对象类型,存在于堆中。

相比于对象类型,基本数据占用的空间非常小。

为什么说是几乎所有对象实例呢? 这是因为 HotSpot 虚拟机引入了 JIT 优化之后,会对对象进行逃逸分析,如果发现某一个对象并没有逃逸到方法外部,那么就可能通过标量替换来实现栈上分配,而避免堆上分配内存

⚠️ 注意 : 基本数据类型存放在栈中是一个常见的误区! 基本数据类型的成员变量如果没有被 static 修饰的话(不建议这么使用,应该要使用基本数据类型对应的包装类型),就存放在堆中。

包装类型的缓存机制了解么?

目的为了提升性能

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

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

两种浮点数类型的包装类 Float,Double 并没有实现缓存机制。如下

Integer i1 = 33;
Integer i2 = 33;
System.out.println(i1 == i2);// 输出 true

Float i11 = 333f;
Float i22 = 333f;
System.out.println(i11 == i22);// 输出 false

Double i3 = 1.2;
Double i4 = 1.2;
System.out.println(i3 == i4);// 输出 false

自动装箱和拆箱以及原理

装箱:就是把基本数据封装成包装类

拆箱:就是把包装类转换成基本数据类型

从字节码中,我们发现装箱其实就是调用了 包装类的valueOf()方法,拆箱其实就是调用了 xxxValue()方法。

因此,

  • Integer i = 10 等价于 Integer i = Integer.valueOf(10)
  • int n = i 等价于 int n = i.intValue();
  • 注意:如果频繁拆装箱的话,也会严重影响系统的性能。我们应该尽量避免不必要的拆装箱操作。

为什么浮点数运算的时候会有精度丢失的风险?

这和计算机保存浮点数的机制有很大关系。计算机是二进制的,计算机在表示一个数字时宽度是有限的,无线循环的小数只能被截断,所以就导致了精度丢失。

如何解决浮点数运算的精度丢失问题?

BigDecimal 可以实现对浮点数的运算,不会造成精度丢失。通常情况下,大部分需要浮点数精确运算结果的业务场景(比如涉及到钱的场景)都是通过 BigDecimal 来做的。

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
BigDecimal c = new BigDecimal("0.8");

BigDecimal x = a.subtract(b);
BigDecimal y = b.subtract(c);

System.out.println(x); /* 0.1 */
System.out.println(y); /* 0.1 */
System.out.println(Objects.equals(x, y)); /* true */

超过 long 整型的数据应该如何表示?

BigInteger 内部使用 int[] 数组来存储任意大小的整形数据。

相对于常规整数类型的运算来说,BigInteger 运算的效率会相对较低。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值