Java后端⾼频知识点学习笔记1---Java基础
1、重载和重写的区别
重载: 同⼀类中多个同名⽅法根据不同的传参来执⾏不同的处理逻辑 ;⽅法名必须相同,参数类型不同、个数不同、顺序不同;返回值类型可以相同也可以不同(因为返回值类型不是 ⽅法签名 的⼀部分)
重写: ⼦类对⽗类的⽅法的实现过程进⾏重新编写 。⽅法名,参数列表和返回值类型都不能改变。抛出的异常范围⼩于等于⽗类,访问修饰符范围⼤于等于⽗类。
什么是⽅法签名?
答:⽅法签名, 区分不同⽅法的标⽰符 ; ⽅法是由⽅法名、形参列表、返回值以及⽅法体构成 ; ⽅法签名是由⽅法名与形参列表构成 ,也就是说,⽅法名和形参列表可以唯⼀地确定⼀个⽅法,与⽅法的返回值没有关系
构造器是否可以被重写,是否可以被重载?
答:构造器可以被重载(Overload),不能被重写(Override)
静态⽅法能否被重写,能否被重载?
答: 静态⽅法不能被重写,可以被重载
静态⽅法可以被继承。 静态⽅法是类在加载时就被加载到内存中的⽅法,在整个运⾏过程中保持不变,因⽽不能重写 ;在Java中,如果⽗类中含有⼀个静态⽅法,且在⼦类中也含有⼀个返回类型、⽅法名、参数列表均与之相同的静态⽅法,那么该 ⼦类实际上只是将⽗类中的该同名⽅法进⾏了隐藏,⽽⾮重写,可以通过类名.⽅法名调⽤被隐藏地⽅法 ;换句话说,⽗类和⼦类中含有的其实是两个没有关系的⽅法,它们的⾏为也并不具有多态性
2、Java⾯向对象的三⼤特性
封装:把⼀个对象的属性私有化,不允许外部对象直接访问这些私有属性,同时提供⼀些可以被外界访问私有属性的⽅法
继承:⼦类继承⽗类的⾮私有属性和⽅法;⼦类可以对⽗类的⽅法进⾏重写,也可以进⾏扩展,拥有⾃⼰的属性和⽅法;⼀个⼦类只能拥有⼀个⽗类,但是可以通过实现多个接⼝来达到多重继承的⽬的
多态:同⼀个操作作⽤在不同对象时,可以产⽣不同的执⾏结果;在Java语⾔中,多态主要有两种表现形式,⽅法的重载和重写
多态分为编译时多态-->重载;运⾏时多态-->重写
重载 :同⼀个类中有多个同名⽅法,根据不同的传参可以执⾏不同的处理逻辑; 在编译时就可以确定到底调⽤哪个⽅法,它是⼀种编译时多态
重写 :⼦类对⽗类的⽅法的实现过程进⾏重新编写,⽅法名,参数列表和返回值类型都不能改变,因此同样的⽅法在⽗类与⼦类中有着不同的表现形式。 Java语⾔中,⽗类的引⽤变量不仅可以指向⽗类的实例对象,也可以指向⼦类的实例对象 。⽽程序调⽤的⽅法在运⾏时才动态绑定,就是引⽤变量所指向的具体实例对象的⽅法,也就是内存中正在运⾏的那个对象的⽅法,⽽不是引⽤变量的类型中的定义的⽅法。这就会出现相同类型的变量调⽤同⼀个⽅法时呈现出多种不同的⾏为特征,这就是多态; 在运⾏时才能确定调⽤哪个⽅法,被称为运⾏时多态
使⽤多态的好处?
多态:同⼀个操作作⽤在不同对象时,可以产⽣不同的执⾏结果; 使⽤多态,可以解决代码的紧耦合的问题,提⾼程序的可扩展性
1. 应⽤程序不必为每⼀个⼦类编写功能调⽤,只需要对抽象⽗类进⾏处理即可,⼤⼤提⾼程序的可复⽤性
2. ⼦类的功能可以被⽗类的⽅法或引⽤变量所调⽤,这叫向上兼容,可以提⾼可扩充性和可维护性
3、Java⾯向对象的5⼤设计原则
原则描述
单⼀职责⼀个类只负责⼀个功能的实现
⾥⽒替换只要⽗类出现的地⽅,都可以⽤⼦类替换
依赖倒置⾼层模块不应该依赖低层模块,⼆者都应该依赖其抽象;就是⾯向接⼝编程
原则描述
接⼝隔离接⼝的功能尽可能单⼀;接⼝更可能细化,不要建⽴臃肿庞⼤的接⼝
开闭尽量通过扩展来⾯对需求的更改或者系统的变化,尽量不要对原有内容修改
4、String、StringBuilder和StringBuffer的区别是什么?
(1)String是不可变的,StringBuilder和StringBuffer是可变的
String不可变,String类中使⽤final关键字修饰char字符数组来保存字符串; private final char value[] ,从Java9开始,String类的实现改⽤byte字节数组存储字符串; private final byte[] value
⽽StringBuilder与StringBuffer都继承⾃AbstractStringBuilder类,在AbstractStringBuilder中也是使⽤字符数组保存字符串char[] value但是没有⽤final关键字修饰,所以这两种对象都是可变的
(2)String和StringBuffer是线程安全的,StringBuilder不是线程安全的
String中的对象的不可变的,所以是线程安全
StringBuffer对⽅法加了synchronized同步锁,所以是线程安全的
StringBuilder没有对⽅法加同步锁,所以不是线程安全的
(3)执⾏效率:StringBuilder最⾼,StringBuffer次之,String最低
每次对String类型进⾏改变的时候,都会⽣成⼀个新的String对象,然后将指针指向新的String对象。StringBuffer每次都会对StringBuffer本⾝进⾏操作,⽽不是⽣成新的对象并改变对象引⽤。相同情况下使⽤StringBuilder相⽐使⽤StringBuffer仅能获得
10%~15%左右的性能提升,但要冒多线程不安全的风险
对于三者使⽤的总结:
当操作少量数据时,优先使⽤String。
当在单线程下操作⼤量数据,优先使⽤StringBuilder类
当在多线程下操作⼤量数据,优先使⽤StringBuffer类
5、String为什么要设置成不可变的?
(1)实现字符串常量池
字符串常量池(String pool)是Java堆内存中⼀个特殊的存储区域,当创建⼀个String对象时,假如此字符串值已经存在于常量池中,则不会创建⼀个新的对象,⽽是引⽤已经存在的对象;假若字符串对象允许改变,那么将会导致各种逻辑错误,⽐如改变⼀个对象会影响到另⼀个独⽴对象,严格来说,这种常量池的思想,是⼀种优化⼿段
(2)允许String对象缓存HashCode
Java中String对象的哈希码被频繁地使⽤, ⽐如在HashMap等容器中;字符串不变性保证了hash码的唯⼀性;因此可以放⼼地进⾏缓存,这也是⼀种性能优化⼿段,意味着不必每次都去计算新的哈希码.
(3)安全性
String被许多的Java类(库)⽤来当做参数,例如:⽹络连接地址URL,⽂件路径path,还有反射机制所需要的String参数等,假若String不是固定不变的,将会引起各种安全隐患;
数据库的⽤户名、密码都是以字符串的形式传⼊来获得数据库的连接,或者在socket编程中,主机名和端⼝都是以字符串的形式传⼊;因为字符串是不可变的,所以它的值是不可改变的,否则⿊客们可以钻到空⼦,改变字符串指向的对象的值,造成安全漏洞。
在并发场景下,多个线程同时读写资源时,由于 String 是不可变的,不会引发线程的问题⽽保证了线程安全
总体来说,String不可变的原因包括 设计考虑,效率优化与安全性 这三⼤⽅⾯
6、⾃动装箱与拆箱
装箱:将基本类型⽤它们对应的引⽤类型包装起来
拆箱:将包装类型转化为基本数据类型
如下代码:
如上代码所⽰,在装箱的时候 ⾃动调⽤ 的是 Integer的valueOf(int) ⽅法;⽽在拆箱的时候⾃动调⽤的是 Integer的intValue() ⽅法。详解: 在调⽤Integer.valueOf()⽅法中,如果数值在[-128,127]之间,将直接从IntegerCache中获取
因为IntegerCache中缓存了[-128,127]之间的值,通过Integer.valueOf()⽅法创建数值在[-128,127]之间的Integer对象时,便返回指向IntegerCache中已经存在的对象的引⽤;否则创建⼀个新的Integer对象
7、抽象类和接⼝的异同?
不同点:
序
号不同点
1在JDK1.8之前接⼝只有⽅法的定义,不能有⽅法的实现;JDK1.8中接⼝可以有默认⽅法(default修饰)和静态⽅法(static修饰)的实现;JDK1.9开
始接⼝中可以定义和实现私有⽅法(普通私有⽅法和静态私有⽅法);⽽抽象类可以有⽅法的定义与实现
2接⼝⾥只能定义静态常量(static final),不能定义普通成员变量;抽象类中既可以定义静态常量,也能定义普通成员变量
3接⼝中不能包含静态代码块,抽象类中可以包含静态代码块
4⼀个类只能继承⼀个抽象类,但是⼀个类可以实现多个接⼝
5接⼝强调的是特定功能的实现,抽象类强调的是所属关系
6main ⽅法:接⼝不能有 main ⽅法;抽象类可以有 main ⽅法,并且可以运⾏它
7接⼝中定义的成员变量,只能是静态常量,默认修饰符 public static final,⽽且必须给其赋初值;接
⼝中定义的成员⽅法,抽象⽅法,默认修饰符为public abstract;抽象类中成员变量默认default(默认,什么也不写,同⼀包中可见),可在⼦类中被重新定义,也可被重新赋值;抽象类中抽象⽅
法被abstract修饰,不能被private、static、synchronzed和native等修饰,必须以分号结尾,不带花括号
8接⼝中不包含构造器;抽象类⾥可以包含构造器,抽象类中的构造器并不是⽤于创建对象,⽽是让其⼦类调⽤这些构造器来完成属于抽象类的初始化操作
9
接⼝被⽤于常⽤的功能,便于⽇后维护和添加删除;抽象类更倾向于充当公共类的⾓⾊,不适⽤于⽇后重新对⽴⾯的代码修改;功能需要累积时⽤抽象类,不需要累积时⽤接⼝相同点:
序号
相同点1接⼝和抽象类都不能被实例化;接⼝的实现类或抽象类的⼦类都只有实现了接⼝或抽象类中的⽅法后才能被实例化
Integer i = 100; // 实际上是Integer.valueOf(100),
int n = i; // 实际上是 i.intValue()
序号相同点
2接⼝和抽象类都可以包含抽象⽅法
8、Java中" == "与equals()⽅法的区别?
" == ": 对于⼋⼤基本数据类型来说,直接⽐较值;如果是引⽤数据类型,则是⽐较内存地址;(因为 Java只有值传递 ,所以对于" == "来说,不管是⽐较基本数据类型,还是引⽤数据类型的变量,本质都是⽐较值,只是引⽤类型变量存的值是对象的地址)
equals():equals()是Object类提供的⽅法之⼀;每⼀个Java类都继承⾃Object类,所以每⼀个对象都具有equals⽅法。Object中的equals⽅法是直接使⽤" == "运算符⽐较的两个对象,所以在没有重写equals⽅法的情况下,equals与" == "运算符⼀样,⽐较的是地
址; 可以通过重写equals⽅法来⽐较两个对象的内容是否相等
9、为什么重写equals()⽅法时必须重写hashCode()⽅法?
equals()和hashCode()⽅法要遵循如下的 原则 :
1、如果两个对象equals()⽅法相等,它们的hashCode返回值⼀定要相同
2、如果两个对象的hashCode返回值相同,但它们的equals()⽅法不⼀定相等java重写和重载的区别
3、两个对象的hashcode()返回值不相等,则可以判定两个对象的内容⼀定不相等
如果只重写equals()⽅法⽽不重写hashCode()⽅法,将会造成equals()⽅法判断出的结果是true,但hashCode()返回值不同的情况,也可能会出现hashCode()⽅法返回值相等,但equals()⽅法相同的情况,因此equals()⽅法与hashCode()⽅法都要进⾏修改,使两者遵循上述原则; 即:equals⽅法被覆盖,则hashCode⽅法也必须被覆盖
问题:为什么需要hashCode()⽅法?
答:使⽤hashCode()⽅法提前校验,避免每⼀次⽐较都调⽤equals⽅法,提⾼效率
⾯试官:你有没有重写过equals()和hashcode()?
答: 在使⽤HashMap的“key”的部分存放⾃定义的对象时,重写过hashCode和equals⽅法,从⽽保证key是唯⼀的
10、Java中的⼋⼤基本数据类型
Java有8中基本数据类型,其中包括
6种数字类型:byte(1)、short(2)、int(4)、long(8)、float(4)、double(8)
1种字符类型:char(2)
1种布尔型:boolean
对于boolean型,官⽅⽂档未明确定义,它依赖于JVM⼚商的具体实现
11、final关键字
final⽤来修饰类、⽅法和变量
1、 final修饰的类不能被继承,final类中的所有成员⽅法都会被隐式的指定为final⽅法 (但是final修饰的类中成员变量是可变的,如果想要final类的成员变量不可变,必须给成员变量增加final修饰)
2、final修饰的⽅法不能被重写
3、 final修饰的变量是常量 ;如果是基本数据类型的变量,则其数值⼀旦在初始化之后便不能更改;如果是引⽤类型的变量,则在对其初始化之后便不能让其指向另⼀个对象
12、static关键字
static关键字主要有以下4种⽤法:
1、修饰成员变量和成员⽅法
被 static 修饰的成员属于类,被类中所有对象共享,可通过 类名.成员变量 或 对象.成员变量的⽅式调⽤
static变量也称作静态变量,静态变量和⾮静态变量的区别是: 静态变量被所有的对象所共享,在内存中只有⼀个副本,它当且仅当在类初次加载时会被初始化 ;⽽⾮静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响;static 成员变量的初始化顺序按照定义的顺序进⾏初始化
static⽅法也称作静态⽅法,静态⽅法不依赖于任何对象就可以进⾏访问,静态⽅法只能访问静态成员,但不能访问类的⾮静态成员,因为⾮静态成员必须依赖具体的对象才能够被调⽤(成员:成员⽅法与成员变量)
2.静态代码块
静态代码块定义在类中⽅法外,类中可以有多个static块
静态代码块在⾮静态代码块之前按照static块的顺序来执⾏每个static块(静态代码块-->⾮静态代码块-->构造⽅法)
⼀个类不管创建多少对象,静态代码块只执⾏⼀次
3.静态内部类
static修饰类的话只能修饰内部类;静态内部类与⾮静态内部类之间存在⼀个最⼤的区别: ⾮静态内部类在编译完成之后会隐含地保存着⼀个引⽤,该引⽤是指向创建它的外围类,但是静态内部类却没有。没有这个引⽤就意味着:<1>它的创建是不需要依赖外围类的创建;<2>它不能使⽤任何外围类的⾮静态成员(成员:成员⽅法与成员变量)
4.静态导包
⽤来导⼊类中的静态资源,1.5之后的新特性;可以指定导⼊某个类中的指定静态资源,并且不需要使⽤类名调⽤类中的静态成员,可以直接使⽤类中静态成员变量和成员⽅法。
静态代码块的加载次序:
⽗类静态代码块-->⼦类静态代码块-->⽗类⾮静态代码块-->⽗类构造函数-->⼦类⾮静态代码块-->⼦类构造函数
13、深拷贝和浅拷贝
浅拷贝:对基本数据类型进⾏值传递;对引⽤数据类型只是进⾏引⽤的传递,并没有在内存中的创建⼀个新的对象,此为浅拷贝
深拷贝:对基本数据类型进⾏值传递;对引⽤数据类型,创建⼀个新的对象,并复制其内容,此为深拷贝
14、Java异常体系
Java中,所有的异常都有⼀个共同的祖先java.lang包中的Throwable类:Throwable类有两个重要的⼦
类:Exception(异常) 和
Error(错误),⼆者都是Java异常体系的重要⼦类,各⾃都包含⼤量⼦类
Error(错误):程序⽆法处理的错误,表⽰运⾏应⽤程序中较严重问题;⼤多数错误与代码编写者执⾏的操作⽆关,⽽表⽰代码运⾏时JVM出现的问题;例如,Java 虚拟机运⾏错误(Virtual MachineError),当 JVM 不再有继续执⾏操作所需的内存资源时,将出现内存溢出(OutOfMemoryError);这些异常发⽣时,JVM⼀般会选择终⽌线程
Exception(异常):程序本⾝可以处理的异常;Exception 类有⼀个重要的⼦类RuntimeException;RuntimeException异常由JVM抛出;还有NullPointerException(要访问的变量没有引⽤任何对象时,抛出该异常);ArithmeticException(算术运算异常,⼀个整数除以0时,抛出该异常)以及 ArrayIndexOutOfBoundsException(数组下标越界异常)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论