java的面试题知识点干货集锦(一)(未分类版)

以下相关知识大多数来自“牛客网”中的各位朋友大神,由本人整理编辑,仅供学习和积累,如有冒犯多多谅解,或联系chenruijia_java@163.com,谢谢各位!

由于资料均来自网络,本人水平有限,难免错漏或不完整,请多多包含,不吝赐教,谢谢各位!


1,JDK,JRE,JVM区别与联系? 

答: JDK : Java Development ToolKit(Java开发工具包)。JDK是整个JAVA的核心,包括了Java运行环境JRE(Java Runtime Envirnment),一堆Java工具(javac/java/jdb等)和Java基础的类库(即Java API 包括rt.jar)。 最主流的JDK是Sun公司发布的JDK,除了Sun之外,还有很多公司和组织都开发了属于自己的JDK,例如国外IBM公司开发了属于自己的JDK,国内淘宝也开发了属于自己的JDK,各个组织开发自己的JDK都是为了在某些方面得到一些提高,以适应自己的需求,比如IBM的JDK据说运行效率就比SUN的JDK高的多。但不管怎么说,我们还是需要先把基础的Sun JDK掌握好。 JDK有以下三种版本: J2SE,standard edition,标准版,是我们通常用的一个版本J2EE,enterpsise edtion,企业版,使用这种JDK开发J2EE应用程序J2ME,micro edtion,主要用于移动设备、嵌入式设备上的java应用程序 我们常常用JDK来代指Java API,Java API是Java的应用程序接口,其实就是前辈们写好的一些java Class,包括一些重要的语言结构以及基本图形,网络和文件I/O等等 ,我们在自己的程序中,调用前辈们写好的这些Class,来作为我们自己开发的一个基础。当然,现在已经有越来越多的性能更好或者功能更强大的第三方类库供我们使用。 

JRE:Java Runtime Enviromental(java运行时环境)。也就是我们说的JAVA平台,所有的Java程序都要在JRE下才能运行。包括JVM和JAVA核心类库和支持文件。与JDK相比,它不包含开发工具——编译器、调试器和其它工具。 

JVM:Java Virtual Mechinal(JAVA虚拟机)。JVM是JRE的一部分,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。JVM 的主要工作是解释自己的指令集(即字节码)并映射到本地的 CPU 的指令集或 OS 的系统调用。Java语言是跨平台运行的,其实就是不同的操作系统,使用不同的JVM映射规则,让其与操作系统无关,完成了跨平台性。JVM 对上层的 Java 源文件是不关心的,它关注的只是由源文件生成的类文件( class file)。类文件的组成包括 JVM 指令集,符号表以及一些补助信息。

我的标注:JDK包括了JRE,JRE包括了JVM

2,关于JDBC的几点知识

 PreparedStatement    &   Statement 
  • PreparedStatement 接口继承 Statement , PreparedStatement 实例包含已编译的 SQL 语句,所以其执行速度要快于 Statement 对象。 
  • 作为 Statement 的子类, PreparedStatement 继承了 Statement 的所有功能。三种方法execute 、 executeQuery 和 executeUpdate 已被更改以使之不再需要参数 (即sql)
  • 在 JDBC 应用中 , 如果你已经是稍有水平开发者 , 你就应该始终以 PreparedStatement 代替 Statement.。也就是说 , 在任何时候都不要使用 Statement. 

基于以下的原因 : 
一 . 代码的可读性和可维护性 . 

虽然用 PreparedStatement 来代替 Statement 会使代码多出几行 , 但这样的代码无论从可读性还是可维护性上来说 . 都比直接用 Statement 的代码高很多档次 : 
stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");
//stmt 是 Statement 对象实例 
perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)"); 
perstmt.setString(1,var1); 
perstmt.setString(2,var2); 
perstmt.setString(3,var3); 
perstmt.setString(4,var4); 
perstmt.executeUpdate(); //prestmt 是 PreparedStatement 对象实例

不用我多说 , 对于第一种方法 . 别说其他人去读你的代码 , 就是你自己过一段时间再去读 , 都会觉得伤心 .

二. PreparedStatement 尽最大可能提高性能 

    语句在被 DB 的编译器编译后的执行代码被缓存下来(也就是预编译) , 那么下次调用时只要是相同的预编译语句就不需要编译 , 只要将参数直接传入编译过的语句执行代码中 ( 相当于一个涵数 ) 就会得到执行 . 这并不是说只有一个 Connection 中多次执行的预编译语句被缓存 , 而是对于整个 DB 中 , 只要预编译的语句语法和缓存中匹配 . 那么在任何时候就可以不需要再次编译而可以直接执行 . 而 statement 的语句中 , 即使是相同一操作 , 而由于每次操作的数据不同所以使整个语句相匹配的机会极小 , 几乎不太可能匹配 . 比如 : 
insert into tb_name (col1,col2) values ('11','22'); 
insert into tb_name (col1,col2) values ('11','23'); 

即使是相同操作但因为数据内容不一样 , 所以整个个语句本身不能匹配 , 没有缓存语句的意义 . 事实是没有数据库会对普通语句编译后的执行代码缓存 . 

当然并不是所以预编译语句都一定会被缓存 , 数据库本身会用一种策略 , 比如使用频度等因素来决定什么时候不再缓存已有的预编译结果 . 以保存有更多的空间存储新的预编译语句 . 

三 . 最重要的一点是极大地提高了安全性 . 

即使到目前为止 , 仍有一些人连基本的恶义 SQL 语法都不知道 . 

String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'"; 

如果我们把 [' or '1' = '1] 作为 varpasswd 传入进来 . 用户名随意 , 看看会成为什么 ? 

select * from tb_name = ' 随意 ' and passwd = '' or '1' = '1'; 

因为 '1'='1' 肯定成立 , 所以可以任何通过验证 . 更有甚者 : 

把 [';drop table tb_name;] 作为 varpasswd 传入进来 , 则 : 

select * from tb_name = ' 随意 ' and passwd = '';drop table tb_name; 有些数据库是不会让你成功的 , 但也有很多数据库就可以使这些语句得到执行 . 

而如果你使用预编译语句 . 你传入的任何内容就不会和原来的语句发生任何匹配的关系 . 只要全使用预编译语句 , 你就用不着对传入的数据做任何过虑 . 而如果使用普通的 statement, 有可能要对 drop,; 等做费尽心机的判断和过滤 . 

我的标注:用 PreparedStatement 代替 Statement

3,关于异常:try-catch-finally 规则( 异常处理语句的语法规则 ) 

1)  必须在 try 之后添加 catch finally 块。try 块后可同时接 catch 和 finally 块,但至少有一个块。 
2) 必须遵循块顺序:若代码同时使用 catch 和 finally 块,则必须将 catch 块放在 try 块之后。 
3) catch 块与相应的异常类的类型相关。 
4) 一个 try 块可能有多个 catch 块。若如此,则执行第一个匹配块。即Java虚拟机会把实际抛出的异常对象 依次和各个catch代码块声明的异常类型匹配,如果异常对象为某个异常类型或 其子类的实例,就执行这个catch代码块, 不会再执行其他的 catch代码块 
5) 可嵌套 try-catch-finally 结构。 
6) 在 try-catch-finally 结构中,可重新抛出异常。 
7) 除了下列情况,总将执行 finally 做为结束: JVM 过早终止(调用 System.exit(int));在 finally 块中抛出一个未处理的异常;计算机断电、失火、或遭遇病毒攻击 

由此可以看出,catch只会匹配一个,因为只要匹配了一个,虚拟机就会使整个语句退出 

经典例题:

先来看一段代码:

public abstract class Test {
    public static void main(String[] args) {
        System.out.println(beforeFinally());
    }
    
    public static int beforeFinally(){
        int a = 0;
        try{
            a = 1;
            return a;
        }finally{
            a = 2;
        }
    }
}

返回1

从结果上看,貌似`finally` 里的语句是在`return` 之后执行的,其实不然,实际上`finally` 里的语句是在在`return` 之前执行的。那么问题来了,既然是在之前执行,那为什么`a` 的值没有被覆盖了?

实际过程是这样的:当程序执行到try{}语句中的return方法时,它会干这么一件事, 将要返回的结果存储到一个临时栈中,然后程序不会立即返回,而是去执行finally{}中的程序, 在执行`a = 2`时, 程序仅仅是覆盖了a的值,但不会去更新临时栈中的那个要返回的值 。执行完之后,就会通知主程序“finally的程序执行完毕,可以请求返回了”,这时,就会将临时栈中的值取出来返回。这下应该清楚了, 要返回的值是保存至临时栈中的。
再来看一个例子,稍微改下上面的程序:
public abstract class Test {
    public static void main(String[] args) {
        System.out.println(beforeFinally());
    }
    
    public static int beforeFinally(){
        int a = 0;
        try{
            a = 1;
            return a;
        }finally{
            a = 2;
            return a;
        }
    }
}

返回 2

 在这里,finally{}里也有一个return,那么在执行这个return时,就会更新临时栈中的值。同样,在执行完finally之后,就会通知主程序请求返回了,即将临时栈中的值取出来返回。故返回值是2.

 结论:
1、不管有木有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
举例:
情况1 :try{} catch(){}finally{} return; 
            显然程序按顺序执行。 
情况2 :try{ return; }catch(){} finally{} return; 
          程序执行try块中return之前(包括return语句中的表达式运算)代码; 
         再执行finally块,最后执行try中return; 
         finally块之后的语句return,因为程序在try中已经return所以不再执行。 
情况3 :try{ } catch(){return;} finally{} return; 
         程序先执行try,如果遇到异常执行catch块, 
         有异常:则执行catch中return之前(包括return语句中的表达式运算)代码,再执行finally语句中全部代码, 
                     最后执行catch块中return. finally之后也就是4处的代码不再执行。 
         无异常:执行完try再finally再return. 
情况4 :try{ return; }catch(){} finally{return;} 
          程序执行try块中return之前(包括return语句中的表达式运算)代码; 
          再执行finally块,因为finally块中有return所以提前退出。 
情况5 :try{} catch(){return;}finally{return;} 
          程序执行catch块中return之前(包括return语句中的表达式运算)代码; 
          再执行finally块,因为finally块中有return所以提前退出。 
情况6 :try{ return;}catch(){return;} finally{return;} 
          程序执行try块中return之前(包括return语句中的表达式运算)代码; 
          有异常:执行catch块中return之前(包括return语句中的表达式运算)代码; 
                       则再执行finally块,因为finally块中有return所以提前退出。 
          无异常:则再执行finally块,因为finally块中有return所以提前退出。 

最终结论 :任何执行try 或者catch中的return语句之前,都会先执行finally语句,如果finally存在的话。 
                  如果finally中有return语句,那么程序就return了,所以finally中的return是一定会被return的, 
                  编译器把finally中的return实现为一个warning。

我的标注:注意执行顺序,关于这个问题可以参考我整理的另一篇文章https://blog.csdn.net/chenruijia170707/article/details/78565532



4, springMVC和spring的几个知识点  
  • springmvc的工作流程/原理
1.springmvc请所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责对请求进行真正的处理工作。 
2.DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller. 
3.DispatcherServlet将请求提交到目标Controller 
4.Controller进行业务逻辑处理后,会返回一个ModelAndView 
5.Dispathcher查询一个或多个ViewResolver视图解析器,找到ModelAndView对象指定的视图对象 
6.视图对象负责渲染返回给客户端。 

为什么用: 
{AOP 让开发人员可以创建非行为性的关注点,称为横切关注点,并将它们插入到应用程序代码中。使用 AOP 后,公共服务 (比 如日志、持久性、事务等)就可以分解成方面并应用到域对象上,同时不会增加域对象的对象模型的复杂性。 
IOC 允许创建一个可以构造对象的应用环境,然后向这些对象传递它们的协作对象。正如单词 倒置 所表明的,IOC 就像反 过来的 JNDI。没有使用一堆抽象工厂、服务定位器、单元素(singleton)和直接构造(straight construction),每一个对象都是用其协作对象构造的。因此是由容器管理协作对象(collaborator)。 
Spring即是一个AOP框架,也是一IOC容器。 Spring 最好的地方是它有助于您替换对象。有了 Spring,只要用 JavaBean 属性和配置文件加入依赖性(协作对象)。然后可以很容易地在需要时替换具有类似接口的协作对象。} 


我的标注:Spring是重点,特别是其主要特性AOP和IOC

5,Web service的理解 

 Web service顾名思义是基于web的服务,它是一种跨平台,跨语言的服务。 

我们可以这样理解它,比如说我们可以调用互联网上查询天气信息的web服务,把它嵌入到我们的B/S程序中,当用户从我们的网点看到天气信息时,会认为我们为他提供很多的服务,但其实我们什么也没做,只是简单的调用了一下服务器上的一端代码而已。Web service 可以将你的服务发布到互联网上让别人去调用,也可以调用别人发布的web service,和使用自己的代码一样。 

它是采用XML传输格式化的数据,它的通信协议是SOAP(简单对象访问协议). 

我的标注:在很多的招聘要求中都有提及,可以进行深入学习。


6,关于管道 

管道实际上是一种固定大小的缓冲区,管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在于内存中。它类似于通信中半双工信道的进程通信机制,一个管道可以实现双向 的数据传输,而同一个时刻只能最多有一个方向的传输,不能两个方向同时进行。管道的容 量大小通常为内存上的一页,它的大小并不是受磁盘容量大小的限制。当管道满时,进程在 写管道会被阻塞,而当管道空时,进程读管道会被阻塞。

我的标注:陌生


7,引用数据类型 VS 基本数据类型 ===》引用传递 VS 值传递

 引用数据类型是引用传递(call by reference),基本数据类型是值传递(call by value) 

值传递不可以改变原变量的内容和地址---》 原因是java方法的形参传递都是传递原变量的副本,在方法中改变的是副本的值,而不适合原变量的 

引用传递 不可以改变原变量的地址,但可以改变原变量的内容---》原因是当副本的引用改变时,原变量 的引用并没有发生变化,当副本改变内容时,由于副本引用指向的是原变量的地址空间,所以,原变量的内容发生变化。

我的标注:1.值传递不可以改变原变量的内容和地址; 2.引用传递不可以改变原变量的地址,但可以改变原变量的内容;

8,常见注解

  •  Override 注解
指明被注解的方法需要 覆写超类中的方法.
如果某个方法使用了该注解,却没有覆写超类中的方法(比如大小写写错了,或者参数错了,或者是子类自己定义的方法),编译器就会生成一个错误.
  • Deprecated 注解
可以修饰类、方法、变量,在java源码中被@Deprecated修饰的类、方法、变量等 表示不建议使用的,可能会出现错误的,可能以后会被删除的类、方法等,如果现在使用,则在以后使用了这些类、方法的程序在更新新的JDK、jar包等就会出错,不再提供支持。     
个人程序中的类、方法、变量用@Deprecated修饰同样是不希望自己和别人在以后的时间再次使用此类、方法。  
当编译器编译时遇到了使用@Deprecated修饰的类、方法、变量时会提示相应的警告信息。
  • Suppresswarnings 注解
可以达到 抑制编译器编译时产生警告的目的,但是很不建议使用@SuppressWarnings注解,使用此注解,编码人员看不到编译时编译器提示的相应的警告,不能选择更好、更新的类、方法或者不能编写更规范的编码。同时后期更新JDK、jar包等源码时,使用@SuppressWarnings注解的代码可能受新的JDK、jar包代码的支持,出现错误,仍然需要修改。
抑制警告的关键字
关键字 用途
all                        to suppress all warnings
boxing                 to suppress warnings relative to boxing/unboxing operations
cast                      to suppress warnings relative to cast operations
dep-ann               to suppress warnings relative to deprecated annotation
deprecation          to suppress warnings relative to deprecation
fallthrough           to suppress warnings relative to missing breaks in switch statements
finally                   to suppress warnings relative to finally block that don’t return
hiding                   to suppress warnings relative to locals that hide variable
incomplete-switch        to suppress warnings relative to missing entries in a switch statement (enum case)
nls                         to suppress warnings relative to non-nls string literals
null                        to suppress warnings relative to null analysis
rawtypes                to suppress warnings relative to un-specific types when using generics on class params
restriction               to suppress warnings relative to usage of discouraged or forbidden references
serial                      to suppress warnings relative to missing serialVersionUID field for a serializable class
static-access          to suppress warnings relative to incorrect static access
synthetic-access    to suppress warnings relative to unoptimized access from inner classes
unchecked            to suppress warnings relative to unchecked operations
unqualified-field-access           to suppress warnings relative to field access unqualified
unused                      to suppress warnings relative to unused code

我的标注:陌生

9,设计模式 之 结构型模式 

 设计模式分为三大类: 

创建型设计模式:单例模式,工厂方法模式,简单工厂模式,建造者模式、原型模式等

结构型设计模式:适配器模式,代理模式,AOP、装饰器模式等

行为型设计模式:观察者模、板方法模式等

  • 结构型模式是描述如何将类对象结合在一起,形成一个更大的结构,结构模式描述两种不同的东西:类与类的实例。故可以分为类结构模式和对象结构模式。 

在GoF设计模式中,结构型模式有: 

1.适配器模式 Adapter 

  适配器模式是将一个 类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 

  两个成熟的类需要通信,但是接口不同,由于开闭原则,我们不能去修改这两个类的接口,所以就需要一个适配器来完成衔接过程。 

2.桥接模式 Bridge 

  桥接模式将 抽象部分与它的实现部分分离,是它们都可以独立地变化。它很好的支持了开闭原则和组合锯和复用原则。实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这些多角度分离出来让他们独立变化,减少他们之间的耦合。 

3.组合模式 Composite 

  组合模式将对象组合成 树形结构以表示部分-整体的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。 

4.装饰模式 Decorator 

装饰模式动态地 给一个对象添加一些额外的职责,就增加功能来说,它比生成子类更灵活。也可以这样说,装饰模式把复杂类中的核心职责和装饰功能区分开了,这样既简化了复杂类,有去除了相关类中重复的装饰逻辑。 装饰模式没有通过继承原有类来扩展功能,但却达到了一样的目的,而且比继承更加灵活,所以可以说装饰模式是继承关系的一种替代方案。 

5.外观模式 Facade 

 外观模式为子系统中的 一组接口提供了统一的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 

外观模式中,客户对各个具体的子系统是不了解的,所以对这些子系统进行了封装,对外只提供了用户所明白的单一而简单的接口,用户直接使用这个接口就可以完成操作, 而不用去理睬具体的过程,而且子系统的变化不会影响到用户,这样就做到了信息隐蔽。 

6.享元模式 Flyweight 

 享元模式为运用共享技术有效的支持大量细粒度的对象。因为它可以通过共享大幅度地减少单个实例的数目,避免了大量非常相似类的开销。. 

      享元模式是 一个类别的多个对象共享这个类别的一个对象,而不是各自再实例化各自的对象。这样就达到了节省内存的目的。 

7.代理模式 Proxy    

为其他对象提供一种代理,并由 代理对象控制对原对象的引用,以间接控制对原对象的访问。 

我的标注:了解,一个项目经常有多种设计模式混合

10,区分编码和编码格式 

编码: 编码就是一个编号(数字)到字符的一种映射关系,就仅仅是一种一对一的映射而已,可以理解成一个很大的对应表格 

java默认的字符集是Unicode(占两个字节byte,一个字节=8比特位bit,所以每个Unicode占用16比特位) 

编码格式:编码格式 是用来序列化或存储编码中提到的那个“编号(数字)”的一种“格式”,包括gbk和utf-8 

    gbk: 是指中国的中文字符,其它它包含了简体中文与繁体中文字符 

    UTF-8: 它是一种全国家通过的一种编码 

我的标注:了解,区分

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值