java基础知识整理
Java面向对象三大特性封装继承多态
封装
- 封装把⼀个对象的属性私有化,同时提供⼀些可以被外界访问的属性的⽅法
继承
- 继承是使⽤已存在的类的定义作为基础建⽴新类的技术,新类的定义可以增加新的数据或新的功能,
- 也可以⽤⽗类的功能,但不能选择性地继承⽗类。通过使⽤继承我们能够⾮常⽅便地复⽤以前的代码。
多态
- 指父类的某个方法被子类重写时,可以产生自己的功能行为,同一个操作作用于不同对象,可以有不同的解释,产生不同的执行结果。
- 继承(多个⼦类对同⼀⽅法的重写)和接⼝(实现接⼝并覆盖接⼝中同⼀⽅法)。
Java的基本类型
基本数据类型是CPU可以直接进行运算的类型。Java定义了以下几种基本数据类型:
- 整数类型:byte,short,int,long
- 浮点数类型:float,double
- 字符类型:char
- 布尔类型:boolean
String是基本数据类型吗?答:不是
String中有哪些方法?
常用方法:
indexOf()
返回指定字符的索引。charAt()
返回指定索引处的字符。replace()
字符串替换。trim()
去除字符串两端空白。split()
分割字符串,返回一个分割后的字符串数组。getBytes()
返回字符串的 byte 类型数组。length()
返回字符串长度。toLowerCase()
将字符串转成小写字母。toUpperCase()
将字符串转成大写字符。substring()
截取字符串。equals()
字符串比较。
Object有哪些方法?
-
Object类,属于java.lang包,位于类层次结构树的顶部。
-
每个类都是Object类的直接或间接的后代。
-
使用或编写的每个类都继承Object的实例方法。
常用方法:
getClass 方法
final 方法、获取对象的运行时 class 对象,class 对象就是描述对象所属类的对象。hashCode 方法
该方法主要用于获取对象的散列值。Object 中该方法默认返回的是对象的堆内存地址。equals 方法
该方法用于比较两个对象,如果这两个对象引用指向的是同一个对象,那么返回 true,否则返回 false。clone 方法
该方法是保护方法,实现对象的浅复制,只有实现了 Cloneable 接口才可以调用该方法,否则抛出 CloneNotSupportedException 异常。toString 方法
返回一个 String 对象,一般子类都有覆盖。默认返回格式如下:对象的 class 名称 + @ + hashCode 的十六进制字符串。wait 方法
当timeout 为 0,即不等待。
==、Equals区别?
- 对象类型不同
- equals():是超类Object中的方法。
- ==:是操作符。
- 比较的对象不同
- equals():用来检测两个对象是否相等,即两个对象的内容是否相等。
- ==:用于比较引用和比较基本数据类型时具有不同的功能
- 运行速度不同
- equals():没有==运行速度快。
- ==:运行速度比equals()快,因为==只是比较引用。
为什么重写equals时必须重写hashCode方法?
- 因为两个相等的对象的
hashCode
值必须是相等。 - 也就是说如果
equals
方法判断两个对象是相等的,那这两个对象的hashCode
值也要相等。 - 如果重写
equals()
时没有重写hashCode()
方法的话就可能会导致equals
方法判断是相等的两个对象,hashCode
值却不相等。
Final的作用?
在Java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)。
- 修饰类
当用final修饰一个类时,表明这个类不能被继承。
- 修饰方法
如果只有在想明确禁止,该方法在子类中被覆盖的情况下才将方法设置为final的。
- 即父类的final方法是不能被子类所覆盖的,也就是说子类是不能够存在和父类一模一样的方法的。
- 修饰变量
- final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
- 当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;
- 如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。
- final修饰一个成员变量(属性),必须要显示初始化。
- 当函数的参数类型声明为final时,说明该参数是只读型的。即你可以读取使用该参数,但是无法改变该参数的值。
StringBuffer、StringBuilder区别?
- StringBuffer稍慢,但线程安全
- StringBuilder更快,但线程不安全,常用
抽象类和接口的区别
面向对象和面向过程的区别?
首先我们面向过程的话,是我们去分析解决问题的一个步骤,然后用我们的函数,把这些步骤一步一步的实现, 然后我们在使用的时候,其实只要一一调用就可以,性能会比较高, 所以是咱们的单片机或者是嵌入式开发,一般都会用这个面向过程去开发。 而面向对象呢,这边的话是把我们构成问题的这些事物,分解成各个对象,就是其实也是万物皆对象, 那我们在建立这个对象的目的呢,其实也不是为了说完成一个个步骤,而是我们在描述某个事物, 然后再解决整个问题过程中发生的一些行为,所以我们面向对象,他们会有一些封装、继承、多态的一些特性, 所以他会比较容易维护,然后也会比较好复用比较好拓展,就是可以设计出一个我们的一个低耦合的一个系统, 但是性能上来说的话会比我们这个面向过程的话,会比要来的低,差不多是这样。
线程、程序、进程的基本概念,以及他们之间是一个怎么样的关系。
- 线程其实跟我们的进程会有点相似,但是线程呢,他其实是一个比我们这个进程哦, 还要更小一点的一个执行单位,一个进程呢,在我们执行的时候的过程中,他会产生一个或多个的一个线程, 所以与我们这个进程不同的是,就是我们在同类的这个多线程,他共享同一块这个内存空间,和我们的一组这个系统资源, 所以这个系统呢,他也会产生一个线程或者说在各个线程之间呢,切换工作时,它的一个负担,会比我们这个进程要小的多, 也正是因为如此,所以线程他其实也会被称为一个轻量级的一个进程。那我们程序的话,其实就是指说,我们的含有指令的,和我们这个数据的这些文件, 那这些文件呢,是被存储在磁盘或者说其他数据呢,的一个存储设备中,也就是说我们这个,其实他更像一个静态的一个代码, 那我们进程就是我们程序,它的一次执行过程中呢,他是这个系统运行程序的一个最基本的一个单位,也正是因为如此, 所以这个进程其实他是一个动态的,就是我们系统如果运行一个程序的话,那就是一个进程,从我们的这个创建啊,然后到我们运行啊, 再到我们的消亡啊,这么一个过程,所以简单来说的话,这个一个进程其实就是一个执行中的一个程序, 他在计算机中的一个指令啊,就是一个指令接着一个指令去执行着,然后同时呢,每个进程呢,他还会占有这个某些系统资源的, 比如说我们的这个CPU的时间,内存空间啊,我们的文件啊,还有我们的输入输出设备的这些使用权啊,所以其实就是这个程序在执行的时候, 他都会被我们这个操作系统啊,载入到我们这个内存中,然后呢我们这个线程呢,他是进程里面划分的一个更小的一个运行单位, 所以线程和进程他有一个最大的不同就是在于,基本上这个每个进程都是一个独立的,但是每个线程就不一定了, 因为同一个进程中里面的这些线程,他们是非常有可能会影响到的,就是我们从另一个角度上来说的话,这个进程呢,他属于操纵系统的范畴, 然后如果主要是同一时间段内啊,然后我们可以同时执行一个或以上的一个程序, 然后这个线程呢,就是在我们同一程序内,几乎是同时执行一个以上的一个程序段,差不多是这样。
深拷贝和浅拷贝的区别?
- 如果是浅拷贝的话,就是我们被复制的对象,这里面所有的变量,大多含与我们这个原来的对象,会有相同的值, 然后所有的,对其他的一个引用呢,他热然是指向我们这个原来的这些对象, 其实简单说的话就是浅拷贝,他仅仅复制了我们所考虑的对象,而不是复制了他所引用的对象。 那如果是我们的深拷贝的话,就是他被复制对象的这些所有变量啊,都是含有跟原来的这个对象相同的值, 那些被引用其他对象的变量呢,就会将指向我们这个被复制的这个新对象,而不是原有的那些被引用的这么一个对象, 其实简单说的话就是我们的一个,深拷贝就是把我们这个复制的对象,所引用的对象呢,都复制了一遍,差不多就是这样。
Cookie和Session的区别?
- 那我们首先就先说一下这个Cookie嘛,Cookie这边,是以这个客户端浏览器用来保存我们数据的一种机制, 好那就是当我们通过这个浏览器去进行我们这个网页访问的时候呢,服务器这边可以把我们某些数据,以这个key-value啊,就是我们那个键值对嘛, 以这种方式写入到我们的Cookie里面,然后存储到我们这个客服端的浏览器, 然后我们客服端下一次再去访问这个服务器的时候,就可以携带这些状态数据,发送到我们的服务器端, 然后我们服务器端里面,这边就可以根据我们的Cookie,Cookie里面携带的内容,去识别我们这个,具体是哪位客户的一个使用者。 那如果是我们的Session的话,就是我们的一个会话,他是属于我们服务端的一个容器对象, 那么在默认情况下啊,就是默认情况下我们这个Session,他会针对我们每个浏览器的一个请求,就是我们的这个Servlet的这个容器, 他都会分配一个Session,我们Session其实他本质上是一个我们的一个ConcurrentHashMap,然后可以存储到我们当前会话,产生的一些状态数据, 嗯,因为我们的这个HTTP协议啊,他本省其实是一个无状态的一个协议,那这种无状态协议也就是说我们服务器他,并不会去知道我们的客户端, 发送过来的一个多次请求,是不是属于同一个用户的,所以我们Session就是来弥补这个HTTP,这个无状态的一个不足嘛,就是我们这个服务器端, 他可以用我们的Session去存储我们的客户端在同一个会话里面的一个多次的一个请求记录,然后,基于我们这个服务端的Session的这些储存机制的话, 在结合我们客服端的这个Cookie机制,然后就可以实现我们这个有状态的一个HTTP协议了,总的来看的话,其实Cookie就是我们这个客服端的一个存储机制, 然后Session是我们服务端的一个存储机制,这两者去结合使用,来去实现我们一个规划的存储。以上是我这个问题的理解。
token
- token类似一个令牌,无状态,用户信息都被加密到token中,服务器收到token后解密就可知道是哪个用户。需要开发者手动添加。
重载和重写有什么区别?
- 重载的话都是在一个类里面的,就是方法名相同的,然后这里面呢,是他们都可能说是参数不同,返回类型也是可以不同的, 那每个重载的方法,或者说这个构造函数,构造函数也是有这个的,都会有一个独一无二的一个参数, 类型的一个列表,那这个最常用的就是我们这个构造器的重载, 比如说我们的有参构造啊,我们的无参构造啊,这些都是最常用的,或者说不同参数的这些构造方法。 重写的话呢,是发生在这个面向对象里面的那个继承,就是发生在我们的父类和子类之间,方法名相同,然后它的一个参数列表也是相同的, 返回值的这个范围就是小于等于我们的父类,然后抛出异常的这个范围,也是小于等于我们的父类,然后他这边的话,就是访问我们的修饰符的范围, 是大于等于我们的父类的,如果我们父类这个方法啊,如果我们父类方法修饰符为private,就是私有化,那么子类就不能重新我们这个方法, 因为他都不能继承到这个方法。然后这边的话,我们的重载和重写都是多态的一种体现,的一种方式嘛,就是我们重载是编译期间的一个活动, 然后重写是我们这个运行期间的一个活动,然后就是我们这个重载是在一个类中定义的这个相同名字和方法,然后就是这个方法的参数列表和类型都要不同, 然后返回型也可以不同,是我们一个重写的标准,然后也可以修改为可见性,然后重写是不一样的,他要求我们这个子类去重写这个基类的方法时候, 要跟父类方法具有相样的,就是基本上都要一样,那他的一个可见性是需要大于等于我们这个基类的一个方法,差不多就是这样。
IO流一般分为几种?
- 如果是按照功能来分的话,一个就是我们的输入流(input),还有就是我们的输出流(output)嘛, 然后如果是按类型来分的话,就是也有分我们的子节流啊,和我们的字符流,那子节流和我们的字符流他们也有一些区别嘛, 子节流他是按照我们的一个8位传输,是以字节为单位的,这么一个输入输出的我们的数据,然后我们的字符流,是以16位的, 然后是以字符为单位的,去输入输出我们的这些数据。
静态变量和普通变量这一块的区别?
- 静态变量的话就是我们static的变量嘛,他们的区别就是说静态变量他这是我们所有的一个对象是共享的, 因为我们在项目运行的时候,他在内存中就只有一个副本,想这个副本的话, 就是说我们在程序初次加载的时候,会被初始化嘛,然后普通变量是在我们对象里面的,他是对象里面所拥有的,就是我们在创建对象的时候,会被初始化, 然后呢他就会有很多的副本,因为我们可能这边new一个对象那边new一个对象,他就存在很多个这个普通的一个变量, 但是这个各个对象之间,他们存在多个副本的话,就各个对象里面这个副本,他们也是互相不会影响的, 然后还有一点就是说我们的static我们的这个静态变量,它的一个初始化顺序,是按照我们定义的这个顺序去进行初始化的,就这些,这就是他们的区别。
自增运算符++和自减运算符
- ++ 和 – 运算符可以放在变量之前,也可以放在变量之后
- 当运算符放在变量之前时(前缀),先自增/减,再赋值
++a
- 当运算符放在变量之后时(后缀),先赋值,再自增/减
a--
例如
-
当 b = ++a 时,先自增(自己增加 1),再赋值(赋值给 b)
-
当 b = a++ 时,先赋值(赋值给 b),再自增(自己增加 1)
-
++a 输出的是 a+1 的值,a++输出的是 a 值
-
“符号在前就先加/减,符号在后就后加/减”
Java的参数传递是传值还是传引用?
- Java世界中的一切对象都是指针(地址)
- 函数调用永远是传值
- 基本类型(包括String类)作为参数传递时,是传递值的拷贝,无论你怎么改变这个拷贝,原值是不会改变的
- 引用类型(包括数组,对象以及接口)作为参数传递时,是把对象在内存中的地址拷贝了一份传给了参数。
- 注意:基本数据类型的封装类Integer、Short、Float、Double、Long、Boolean、Byte、Character虽然是引用类型, 但它们在作为参数传递时,也和基本数据类型一样,是值传递。
Continue、break和return的区别是什么?
在循环结构中,当循环条件不满足或者循环次数达到要求时,循环会正常结束。 但是,有时候可能需要在循环的过程中,当发生了某种条件之后 ,提前终止循环, 这就需要用到下面几个关键词:
continue
:指跳出当前的这一次循环,继续下一次循环。break
:指跳出整个循环体,继续执行循环下面的语句。
return
:用于跳出所在方法,结束该方法的运行。return 一般有两种用法:
return;
:直接使用 return 结束方法执行,用于没有返回值函数的方法return value;
:return 一个特定值,用于有返回值函数的方法
下列语句的运行结果是什么?
|
|
运行结果:
|
|
Java异常
异常基本类型
- 异常类的基本类型是
Throwable
类 - 两大子类分别是
Error
和Exception
Error
- 系统错误由Java虚拟机抛出,用
Error
类表示。Error
类描述的是内部系统错误 - 例如:Java虚拟机崩溃。在程序中不会对
Error
异常进行捕捉和抛出。
Exception
异常Exception
又分为RuntimeException
(运行时异常)和CheckedException
(检查时异常)
RuntimeException(运行时异常)
- 程序运行过程中才可能发生的异常,一般为代码的逻辑错误
- 例如:类型错误转换,空指针异常、找不到指定类等
CheckedException(检查时异常)
- 编译期间可以检查到的异常,必须显式的进行处理(捕获或者抛出到上一层)
- 例如:
IOException
,FileNotFoundException
,SQLException
等
异常处理
throws(声明异常)
- 在方法头中显式声明该异常,以便于告知方法调用者此方法有异常
- 若父类的方法没有声明异常,则子类继承方法后,也不能声明异常
try-catch(捕获异常)
- 若执行
try
块的过程中没有发生异常,则跳过catch
子句 - 若是出现异常,
try
块中剩余语句不再执行。 - 再判断
catch
块的异常类是否是捕获的异常类型,匹配后执行相应的catch
块中的代码。 - 如果有
finally
的话进入到finally
里面继续执行。 try ctach fianally
中有return
时,会先执行return
,但是不会返回。在执行完finally
后进行返回catch
语句可以有一个或多个,finally
语句最多一个
throw,throws关键字区别
throw
关键字是用于方法体内部,用来抛出一个Throwable类型的异常throws
关键字用于方法体外部的方法声明部分,用来声明方法可能会抛出某些异常
|
|
常见的几种异常
RuntimeExceptionjava.lang.ArithmeticException(算术异常)
- java.lang.
NullPointerException
(空指针异常) - java.lang.
ClassCastException
(类型转换异常) - java.lang.
IllegalArgumentException
(不合法的参数异常) - java.lang.
IndexOutOfBoundsException
(数组下标越界异常)
java.io.IOException(IO流异常)
- java.lang.
ClassNotFoundException
(没找到指定类异常) - java.lang.
NoSuchFieldException
(没找到指定字段异常) - java.lang.
NoSuchMetodException
(没找到指定方法异常) - java.lang.
IllegalAccessException
(非法访问异常) - java.lang.
InterruptedException
(中断异常)
静态方法为什么不能调用非静态方法?
- 静态方法是属于类的,在类加载的时候就会分配内存,可以通过类名直接访问。而非静态成员属于实例对象,只有在对象实例化之后才存在,需要通过类的实例对象去访问。
- 在类的非静态成员不存在的时候静态成员就已经存在了,此时调用在内存中还不存在的非静态成员,属于非法操作。
静态方法和实例方法有何不同?
调用方式
- 在外部调用静态方法时,可以使用
类名.方法名
的方式,也可以使用对象.方法名
的方式,而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。 - 不过,需要注意的是一般不建议使用
对象.方法名
的方式来调用静态方法。这种方式非常容易造成混淆,静态方法不属于类的某个对象而是属于这个类。
因此,一般建议使用类名.方法名
的方式来调用静态方法。
|
|
访问类成员是否存在限制
- 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),不允许访问实例成员(即实例成员变量和实例方法),而实例方法不存在这个限制。