Java基础(一)

1.一次编译到处运行

同一个Java源码只需要编译一次,就可以在不同的机器上运行,而不需要重新编译。字节码是不能直接运行的,需要JVM翻译成机器码。
JVM是Java跨平台的关键,Java源代码编译成字节码.class, JVM负责将字节码翻译成各种平台下的机器码并运行。

2.一个Java文件中能有多个类吗?(不含内部类)

可以有多个类,但是只能由一个public修饰的类,且这个类名必须和文件名一样

3.Java访问权限符

修饰成员变量或成员方法时private:类内,default:同包,protected: 同包及子类,public:任意
修饰类(不包括内部类)只有两种:default:同包, public:任意

4.Java数据类型

基本数据类型:byte、short、int、long、float、double、char、boolean
引用类型即对象的引用,有三类:数组、类、接口。本质是通过指针,指向堆中对象所持有的内存空间

5.成员变量和局部变量区别

成员变量类中定义,也叫类属性,有默认初始值、非静态变量在堆中和对象共存亡,静态变量在方法区和类对象共存亡

扩展:
JDK1.6 方法区在永久代,字符串常量池也在永久代
JDK1.7方法区在永久代(占用JVM的内存),字符串常量池在堆空间。
JDK1.8之后,方法区在元空间(直接占用电脑主机的内存),且字符串常量池被放到堆空间去了

局部变量方法或代码块中定义,没默认初始值,必须得手动赋初始值,存在栈内存中,作用范围结束,空间自动释放

扩展:
栈是运行时单位,而堆是存储时单位,JVM的栈是线程私有的,栈里面放的是一个个栈帧,每个方法执行伴随入栈、执行结束出栈。栈中有:
局部变量表:存的是基本数据类型和对象引用和返回值类型、如果是构造器方法或对象方法(不是静态方法)第一个位置放的是对象引用this
操作数栈:保存中间结果
动态链接、方法返回地址、一些附加信息

6.为啥要有包装类?

Java是面向对象的语言,设计理念是一切皆对象,但是8中基本数据类型没有对象的特征,为了解决这个问题就定义了他们对应的引用类型
8种基本数据类型,用起来很方便,但是Java种所以对象都继承自Object类,所有的引用类型都可以当作Object类使用,但是基本数据类型却不行。有了包装类,这种问题就得到了简化。

7.Java中的装箱、拆箱

自动装箱、拆箱是JDK1.5提供的功能
自动装箱就是把一个基本数据类型转化成其对应的包装类型、自动拆箱就是包装类转化成基本数据类型。
通过自动装、拆箱可以简化基本数据类型和包装类之间的转换过程。

8.Integer和Double类型如何判断相等?

不同数据类型当然不能直接用等于号、 也不能变成字符串进行比较,浮点数有小数点,整数没有一定不相等,也不能用他们的compareTo方法。这个方法只能对相同类型进行比较

可以把他们先转化成相同的数据类型再比较,比如都转化成基本数据类型,然后用==比较

9.int和Integer的区别和比较

int和Integer比较会进行自定拆箱,对其数值进行比较。
Integer a = new Integer(3); 这是直接在堆空间创建一个Integer 对象值为3
Integer b = 3; 小于128是冲缓存池中取出的一个对象
Integer c = 128; 这个在堆空间创建的一个对象
因此会有下列情况:

Integer a = new Integer(3);
Integer b = 3, c = 3; //将3自动装箱成为Integer类型,实际执行的方法是Integer.valueOf(3)  
a==b //false
//Integer.valueOf(x)方法,在x<128时是从缓存中取得,>=128时是new Integer(128)的
b==c //true
Integer d = new Integer(3),e = new Integer(3)
d==e //false 这是两个对象
Integetr f = 128, g = 128;
f==g//false 这也是两个new出来的对象

10.说说对面向对象的理解

面向对象是一种优秀的程序设计思想,有三大特性:封装、继承、多态。面向对象更类似人类的自然思维方式,静事物抽象为类,使得软件系统的组件可以直接映像到客观世界。注重事情的参与者和各自需要做什么。而面向过程是将任务拆解称为一系列步骤,注重每个步骤干什么和执行顺序。

举个人用洗衣机洗衣服的例子:
面向过程: 1.打开洗衣机盖子、 2.放入衣服、3.放洗衣服、4.启动洗衣机、5.取出衣服挂起来
面向对象:人、洗衣机两个对象、人有使用操作洗衣机的方法,有挂衣服的方法、洗衣机有洗衣服的方法。
面向对象的性能更低,因为类调用方法需要实例化,有较大的资源开销,所有需要性能的适合就采用面向过程,比如单片机、Linux。但是开发低耦合易维护、易扩展的系统就需要用到面向对象。

11.封装、继承、多态。

封装:将类的某些信息私有化、不让外部直接访问,通过提供公共的方法来实现对隐藏信息的操作和访问,隐藏实现细节,提高安全性。
比如一个类中有一个属性name, 我需要name属性的设置必须有一定命名规则,比如加一个前缀字符串user。我就可以在set方法中完成这个操作,使得属性name的值一定是user开头的
继承:继承是类与类的一种关系,是IS-A的关系,子类拥有父类所有属性和方法(由于封装特性,子类不能调用父类的私有方法和属性,通过反射可以获取父类然后获取它的私有方法),实现代码复用减少重复代码。

多态:基于对象所属类的不同,外部对同一个方法的调用和实际执行逻辑不同,提高扩展性降低耦合度。
例如:父类引用指向子类对象,调用时使用变量名.方法名,调用的实际是子类重写的方法。当我们想要调用其他子类的方法时,只需要让引用指向其他子类,不需要改具体调用处的代码

多态的前提:继承关系(或接口关系),子类重写父类方法、父类引用指向子类对象
弊端:无法调用子类特有方法,只能通过向下转型再调用,多态只适用于方法,不适用属性,调用的均是父类属性

12.重载与重写的区别

重载发生在一个类中,多个方法名相同,参数列表不同。这些方法构成重载关系。重载和方法的返回值及权限修饰符无关。
重写发生在父类子类中,子类方法想要和父类方法构成重写关系,则他们的方法名、参数列表必须与父类相同。返回值要小于等于父类方法,抛出异常要小于等于父类方法,访问修饰符要大于等于父类方法。父类private不能对其重写。构造方法不能重写

13.介绍Object类中的方法

Class<?> getClass() 返回该对象运行时类
boolean equals(Object obj) :判断该对象与指定对象是否相同
int hashCode(): 返回该对象的hashCode值。
String toString() 返回该对象字符串表示,默认是运行时类型@十六进制的hashCode值
clone() 获得一个当前对象的副本
wait()、notify()、notifyAll()、 控制线程暂停和运行
finalize() 垃圾回收的时候调用,且垃圾回收器最多调用这个方法一次,这个方法何时调用和是否调用都不确,所有不要主动调用finalize() 方法

14.hashCode() 和 equals() 关系,为什么要重写这两个方法

hashCode()相同则equals()不一定相等,equals()相等,则他们hashCode()一定相同
例如:向HashSet中添加元素的时候,为了效率,就是用其hashCode()确定存放位置,假设位置有元素了就用equals方法判断元素是否重复,重复就不添加,不重复就用链式结构保存在他这个元素后面。

Object类的equals() 方法默认是用==来比较的,也就是两个对象是一个地址的同一个对象时,才能返回相等。而实际的业务中,通常需求都是两个对象只有内容相同认为他们是相等的,所有得重写equals()方法。

一般要求重写equals() 必须重写hashCode(), 因为很多内置数据结构,比如HashSet是先判断hashCode()是否相同,再用equals判断是否相等。如果你重写了equals而没有重写hashCode,可能导致两个对象equals相等而hashCode不相等,这就违背了hashCode和equals关系了,可能导致HashSet里面出现重复的(equals相等)对象。

15.String 能被继承吗?

不能,String类是被final修饰的,不能被继承。
String在Java中是不可变类,其保存字符串的成员变量是final的,之所以设计成为不可变类,是出于安全和性能考虑:
字符串被广泛使用,会用来存敏感信息,比如账号、密码、文件路径等如果可变,可能会被篡改,出现SQL注入,访问危险文件等
多线程中,只有不变的对象和值才是线程安全的,可以在多线程中共享数据。String天然不可变,当一个线程修改了字符串的值,只会产生一个新的字符串对象。其他线程访问不会产生副作用。
字符串被大量应用在集合容器中,尤其是HashSet这种散列集合,每次放入元素都要计算对象的hashCode().来确定对象存放位置,String不可变就不用重复计算hashcode,只需要用缓存的hashcode即可
当字符串不可变时,字符串常量池才有意义。字符串常量池减少创建相同字面量的字符串,让不同的引用指向同一个字符串,节约堆内存。
String是不可变的类,当然也就不能被继承,否则子类继承String类重写其方法,强行改变字符串的值,违背String类设计的初衷

16.String 和StringBuilder、StringBuffer区别

String类是不可变类,一旦创建,这个字符序列就不可改变,直到对象被销毁
StringBuffer和StringBuilder都是代表可变字符串,有append()、insert()、 reverse() 等方法改变这个对象的字符序列。
通过StringBuilder生成了最终想要的字符串后,可以用它的toString()方法将其转换为一个String对象。

StringBuilder和StringBuffer有共同的父类AbstractStringBuilder, 两个类的构造方法和成员方法基本相同,
不同的是StringBuilder是线程不安全的,StringBuffer是线程安全的,所有StingBuilder效率略高,一般优先考虑StringBuilder类

17. 使用字符串时,“” 直接赋值和 new String(“”) 的区别

StringTable(字符串常量池)https://blog.csdn.net/weixin_44179010/article/details/121888449
String s = “hello” 时,JVM会使用常量池来管理这个字符串字面量, 如果常量池中没有hello,就把hello存入常量池,并把其引用赋值给s, 如果常量池存在hello直接将其引用返回给s。
String s = new String(“hello”), 执行这个代码,首先堆空间创建一个字符串的引用,然后JVM使用常量池管理hello这个字面量,s的值是堆空间的字符串引用的地址,堆空间引用指向常量池地址。

18.字符串相加的底层如何实现

如果拼接的都是字面量,则在编译期就会优化成一个完整字符串,和直接写一个完整字符串一样

如果拼接的字符串包含变量,编译器会采用StringBuilder对其优化,即自动创建一个StringBuilder并调用其append方法,把字符串拼接到一起
如果是在循环里进行有变量的字符串拼接,会创建很多StringBuilder,会损失性能

最好就是,字符串字面量直接用+号拼接、变量用StringBuilder或者StringBuffer、两个字符串拼接包括变量用concat()方法

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

甲 烷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值