Java面试题

本文详细列举了Java面试中常见的知识点,涵盖了基础语法、数据类型、字符串、面向对象、集合框架、异常处理、多线程、IO流、反射、设计模式、数据库操作等多个方面,包括基本概念、用法、优缺点、注意事项以及常见面试题的解答,是准备Java面试的全面参考资料。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

是什么 有什么作用 优点 缺点 应用场景 和其他的异同

在同一个类中可以有多个main方法。

八种基本数据类型的大小,以及他们的封装类。

八种基本数据类型,int ,double ,long ,float, short,byte,character,boolean

对应的封装类型是:Integer ,Double ,Long ,Float, Short,Byte,Character,Boolean

基本型别 大小 最小值 最大值
boolean —– —– ——
char 16-bit Unicode 0 Unicode 2^16-1
byte 8-bit -128 +127
short 16-bit -2^15 +2^15-1
int 32-bit -2^31 +2^31-1
long 64-bit -2^63 +2^63-1
float 32-bit IEEE754 IEEE754
double 64-bit IEEE754 IEEE754
i
自动转换:位数小的转为位数大的,比如int转为double
强制转换:位数大的转为位数小的

i++i++i
int i=0;
System.out.println(i++);//0
System.out.println(++i);//1
i++先赋值再自增,下次引用i时再增
++i和i++相反

finally
finally块会被执行无论是否抛出异常,就算try里面有return也会执行,除非在try中写System.exit(1) 或 System.exit(0),,就会终止程序,不执行finally.

在java 中退出程序,经常会使用System.exit(1) 或 System.exit(0)。
  当 status为0 时正常退出程序, 当status为非0数字时异常退出。 终止当前的Java虚拟机。

在Mybatis中,有两种占位符
#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号

  • mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值

  • $ {}对传递进来的参数原样拼接在SQL中

  • #{}是预编译处理,$ {}是字符串替换。

  • 使用#{}可以有效的防止SQL注入,提高系统安全性。

**ps:**预编译是提前对SQL语句进行预编译,而其后注入的参数将不会再进行SQL编译。我们知道,SQL注入是发生在编译的过程中,因为恶意注入了某些特殊字符,最后被编译成了恶意的执行操作。而预编译机制则可以很好的防止SQL注入。

Mybatis中传递多个参数的4种方法总结

1、@Param注解传参法
#{}里面的名称对应的是注解 @Param括号里面修饰的名称。
这种方法在参数不多的情况还是比较直观的,推荐使用。

2、Map传参法
#{}里面的名称对应的是 Map里面的key名称。
这种方法适合传递多个参数,且参数易变能灵活传递的情况。

 try{
            //映射文件的命名空间.SQL片段的ID,就可以调用对应的映射文件中的SQL


            /**
             * 由于我们的参数超过了两个,而方法中只有一个Object参数收集
             * 因此我们使用Map集合来装载我们的参数
             */
            Map<String, Object> map = new HashMap();
            map.put("start", start);
            map.put("end", end);
            return sqlSession.selectList("StudentID.pagination", map);
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    <!--分页查询-->
    <select id="pagination" parameterType="map" resultMap="studentMap">

        /*根据key自动找到对应Map集合的value*/
        select * from students limit #{start},#{end};

    </select>

Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?

如果配置了namespace那么当然是可以重复的,因为我们的声明实际上就是namespace + id

如果没有配置namespace的话,那么相同的id就会导致覆盖了。

为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?(mybatis和hibernate的区别)

hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql。而mybatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写sql来实现和管理。

通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?

Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和查找策略。

Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理代理对象,代理对象代理会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。

关联绑定有两种实现方式:

一种是通过注解绑定,就是在接口的方法上面加上@ Select @ Update等注解里面包含Sql语句来绑定

另外一种就是通过xml里面写SQL来绑定,在这种情况下,要指定xml映射文件里面的名称空间必须为接口的全路径名。

Java中==与equals的区别及理解

区别:

1、对于==,如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;

如果作用于引用类型的变量,则比较的是所指向的对象的地址

2、对于equals方法,注意:equals方法不能作用于基本数据类型的变量

如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;

诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。

equals()是对字符串的内容进行比较

String str1 = “abc”;
String str2 = “abc”;
System.out.println(str1==str2); //true

因为String是用final修饰的,所以会放在常量池。
解释:先在栈中创建一个对 String类的对象引用变量str1,然后通过引用去字符串常量池 里找有没有"abc",如果没有,则将"abc"存放进字符串常量池。如果已经有”abc” 则直接令str2指向“abc”。这里我们在第三行代码中已经将“abc”这个字符串存储进了常量池。所以str2和str1指向的是同一个“abc”,返回true。

面向对象的四大基本特性?
抽象 继承 封装 多态
多态的三个要素:继承、重写和父类引用指向子类对象。

& 与 && 的区别?
&运算符是:逻辑与;&&运算符是:短路与。
&和&&在程序中最终的运算结果是完全一致的,只不过&&存在短路现象,当&&运算符左边的表达式结果为false的时候,右边的表达式不执行,此时就发生了短路现象。如果是&运算符,那么不管左边的表达式是true还是false,右边表达式是一定会执行的。这就是他们俩的本质区别。

访问修饰符public、private、protected、以及不写(default默认)时的区别?
在这里插入图片描述
类的成员不写访问修饰时默认为default。默认对于同一个包中的其他类相当于公开(public)。外部类的修饰符只能是public或默认,类的成员(包括内部类)的修饰符可以是以上四种。一个Java文件中,如果有多个类,只能有一个类被修饰为public,类名必须和文件名相同

float f=3.4;是否正确?
不正确。3.4是双精度数,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F。

java 重载与重写是什么?有什么区别?

重载(Overload)是让类以统一的方式处理不同类型数据的一种手段,实质表现就是多个具有不同的参数个数或者类型的同名函数(返回值类型可随意,不能以返回类型作为重载函数的区分标准)同时存在于同一个类中,是一个类中多态性的一种表现(调用方法时通过传递不同参数个数和参数类型来决定具体使用哪个方法的多态性)。

构造方法可以重载,不可以重写

重写和重载
Java中规定,被子类重写的方法不能拥有比父类方法更加严格的访问权限。当父类中方法的访问权限修饰符为private时,该方法只能被自己的类访问,不能被外部的类访问,在子类是不能被重写的

Super关键字的使用
当需要在子类中调用父类的被重写方法时,要使用super关键字。

重写与重载之间的区别
方法重载:
1、同一个类中
2、方法名相同,参数列表不同(参数顺序、个数、类型)
3、方法返回值、访问修饰符任意
4、与方法的参数名无关
方法重写:
1、有继承关系的子类中
2、方法名相同,参数列表相同(参数顺序、个数、类型),方法返回值相同
3、访问修饰符,访问范围需要大于等于父类的访问范围
4、与方法的参数名无关

class Animal{
 public void move(){
  System.out.println("动物可以移动");
 }
}
class Dog extends Animal{
 public void move(){
  System.out.println("狗可以跑和走");
 }
 public void bark(){
  System.out.println("狗可以吠叫");
 }
}
public class TestDog{
 public static void main(String args[]){
  Animal a = new Animal(); // Animal 对象
  Animal b = new Dog(); // Dog 对象
  a.move();// 执行 Animal 类的方法
  b.move();//执行 Dog 类的方法
  b.bark();
 }
}
//以上实例编译运行结果如下:
TestDog.java:30: cannot find symbol
symbol : method bark()
location: class Animal
    b.bark();  

向上转型和向下转型

转型基础:有继承关系。

向上转型(upcasting):将子类对象转为父类对象。父类对象可以是接口。(儿子当爸爸)向上转型时,子类的新有的方法都会遗失掉。此处父类对象可以是接口

向下转型(downcasting):父类引用的对象转换为子类类型,需要强转。(爸爸当儿子)

Java 中的final关键字有哪些用法?

修饰类:表示该类不能被继承;
修饰方法:表示方法不能被重写;
修饰变量:表示变量只能一次赋值以后值不能被修改(常量)

指出下面程序的运行结果。
在这里插入图片描述
执行结果:1a2b2b。创建对象时构造器的调用顺序是:先初始化静态成员,然后调用父类构造器,再初始化非静态成员,最后调用自身构造器。静态代码块只初始化一次

int 和 Integer 有什么区别

int 是基本数据类型
Integer是其包装类,注意是一个类。
为什么要提供包装类呢???
一是为了在各种类型间转化,通过各种方法的调用。否则 你无法直接通过变量转化

接口和抽象类的区别?
接口是公开的,不能有私有的方法或变量,接口中的所有方法都没有方法体,通过关键字interface实现。接口中的成员变量可以为public 缺省 final static

抽象类是可以有私有方法或私有变量的,通过把类或者类中的方法声明为abstract来表示一个类是抽象类,被声明为抽象的方法不能包含方法体(抽象类可以包含非抽象方法)

接口只有定义,不能有方法的实现,java 1.8中可以定义default方法体,而抽象类可以有定义与实现,方法可在抽象类中实现。

实现接口的关键字为implements,继承抽象类的关键字为extends。一个类可以实现多个接口,但一个类只能继承一个抽象类。所以,使用接口可以间接地实现多重继承。

抽象类
1.抽象类的的方法必须全部都被子类实现,如果子类没有全部实现,那么子类也是抽象类。

    2.抽象类的方法不一定全部都是抽象的方法,有些方法是可以自己先实现,之后子类直接使用就好。也就是说,其实一个抽象类可以完全就是没有抽象方法,就只有在类名前面加上一个abstract就好。 但是这么做我觉得没有什么实际性的必要。

    3.抽象类不能创建实例对象,但是可以有自己的构造方法。这两者看上去似乎有些矛盾,但是其实也是合理的。因为抽象类是可以有自己的成员变量的,之后子类继承之后,还得调用父类的构造函数。

java 中final的作用?
final关键字主要用在三个地方:变量、方法、类;
a.对于一个final变量,必须要赋初始值,而且是只能初始化一次。
如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;
如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
被fianl修饰的成员变量赋值,有两种方式:1、直接赋值 2、在构造方法中赋初值。
b.当用final修饰一个类时,表明这个类不能被继承。
final类中的成员变量可以可以根据实际需要设计为final, final类中的所有成员方法都会被隐式地指定为final方法。
一般来说工具类我们往往都会设计成为一个fianl类。在JDK中,被设计为final类的有String、System等。
d.使用final修饰方法时,表名此方法不能被重写;
1.一个类的private方法会隐式的被指定为final方法;
2.如果父类中有final修饰的方法,那么子类不能去重写;
e.使用final方法的原因:
1.把方法锁定,以防任何继承类修改它的含义;

2.在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,
可能看不到内嵌调用带来的任何性能提升(现在的Java版本已经不需要使用final方法进行这些优化了)

String类可以被继承吗?
String类在声明时使用final关键字修饰,被final关键字修饰的类无法被继承

String和Object的初始值都是null,但是null会优先匹配引用类型参数为String的方法,

在这里插入图片描述
解答:这道题考察的是日期中获取的月份是从0开始的,因此会比我们日常的月份少1,这个题答案是8 8。

在Java中,为什么abstract不能修饰属性
被abstract修饰的内容都是暂未被实现的,比如类、方法。
属性之所以不能被abstract修饰,是因为属性不存在"尚未被实现"的状态。
比如你可能会联想到int age; 或是String name; 但可惜的是,在申明变量时,int会默认给age赋予初始值0,String会默认给name赋予初始值""。因此属性达不到"尚未被实现的状态",从而不能被abstract修饰。

static关键字
这里要强调一下:

static修饰的成员变量和方法,从属于类

普通变量和方法从属于对象

静态方法不能调用非静态成员,编译会报错

显然,被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。

static可以用来修饰类,修饰类的成员方法、类的成员变量,另外也可以编写static代码块来优化程序性能

虽然在静态方法中不能直接访问(实例化对象可以访问)非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法和静态成员变量,不存在this一说。

**特别说明:**static方法是属于类的,非实例对象,在JVM加载类时,就已经存在内存中,不会被虚拟机GC回收掉,这样内存负荷会很大,但是非static方法会在运行完毕后被虚拟机GC掉,减轻内存压力

static块的作用
静态初始化块的作用就是:提升程序性能。
因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行

**Ps:**Java中的static关键字不会影响到变量或者方法的作用域。在Java中能够影响到访问权限的只有private、public、protected(包括包访问权限)这几个关键字

static能作用于局部变量么?

static是不允许用来修饰局部变量。

在这里插入图片描述
来源于:https://blog.csdn.net/kuangay/article/details/81485324

在java中能用private修饰类吗?

当然可以了! (但是基本不推荐这样写)
但是只能修饰内部类-----外部类不能用private修饰,不然直接就报错!
但是,这个地方一定要注意了:内部类中方法只能是static的,因此,内部类也要声明为静态的!

public class aa {
     static class InnerClass {
        public static void doSomething() {
            System.out.println("private Class doSomething");
        }

        public static void main(String[] args) {
            InnerClass.doSomething();
        }
}}

java中String类设计成不可变的原因
如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的。不能改变状态的意思是,不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,引用类型指向的对象的状态也不能改变。

在这里插入图片描述
s只是一个引用,它指向了一个具体的对象,当s=“abcd”; 这句代码执行过之后,又创建了一个新的对象“abcdel”, 而引用s重新指向了这个新的对象,原来的对象“abcd”还在内存中存在,并没有改变。

为什么不可变

public final class String implements Serializable, Comparable<String>, CharSequence {
    private final char[] value;
    private int hash;
首先,String类是用final关键字修饰,这说明String不可继承。
其次,再看下面,String类的主力成员字段value是个char[]数组,而且是用final修饰的。final修饰的字段创建以后就不可改变。

不可变好处
因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。
在大量使用字符串的情况下,可以节省内存空间,提高效率。
不可变缺点

Java String和byte类型互转

 byte[] byteArray = str.getBytes();  //转byte[]
 String str = new String(byteArray);  //转String

7.java 中操作字符串都有哪些类?它们之间有什么区别?
操作字符串的类有:String、StringBuffer、StringBuilder。

String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。

StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。

1.JDK 和 JRE 有什么区别?
JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。
JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的运行提供了所需环境。
具体来说 JDK 其实包含了 JRE,同时还包含了编译 java 源码的编译器 javac,还包含了很多 java 程序调试和分析的工具。简单来说:如果你需要运行 java 程序,只需安装 JRE 就可以了,如果你需要编写 java 程序,需要安装 JDK。

所有散列函数都有如下一个基本特性:
1:如果a=b,则h(a) = h(b)。
2:如果a!=b,则h(a)与h(b)可能得到相同的散列值。

8.String str="i"与 String str=new String(“i”)一样吗?
不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。

12.普通类和抽象类有哪些区别?
普通类不能包含抽象方法,抽象类可以包含抽象方法。
抽象类不能直接实例化,普通类可以直接实例化。

14.接口和抽象类有什么区别?
实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
构造函数:抽象类可以有构造函数;接口不能有。
main 方法:抽象类可以有 main 方法,并且我们能运行它;接口不能有 main 方法。
实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符。
15.java 中 IO 流分为几种?
按功能来分:输入流(input)、输出流(output)。

按类型来分:字节流和字符流。

字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。

3.接口默认的修饰符

所有的接口 的 成员变量默认都是:puiblic static final 的

所有接口的 方法默认都是:public abstract

25. ArrayList 和 LinkedList 的区别是什么?

最明显的区别是 ArrrayList底层的数据结构是数组,支持随机访问,而 LinkedList 的底层数据结构是双向循环链表,不支持随机访问。使用下标访问一个元素,ArrayList 的时间复杂度是 O(1),而 LinkedList 是 O(n)。
三者中只有Vector是线程安全的类,自然ArrayList和LinkedList在多线程中是不安全的

1、什么是Spring?

Spring是一个反转控制IOC和AOP的开发框架和平台

IOC:反转控制–将创建对象的方式反转

自己创建、维护对象-->由spring完成创建、注入

反转控制就是反转了对象的创建方式,从自己创建反转给了程序

DI:依赖注入–实现IOC需要DI做支持

注入方式:set、构造方法、字段 注入

注入类型:值类型(8大数据类型)、引用类型(对象) 注入

spring bean的作用域

  1. singleton——唯一 bean 实例
    当一个 bean 的作用域为 singleton,那么Spring IoC容器中只会存在一个共享的 bean 实例,并且所有对 bean 的请求,只要 id 与该 bean 定义相匹配,则只会返回bean的同一实例。

  2. prototype——每次请求都会创建一个新的 bean 实例
    当一个bean的作用域为 prototype,表示一个 bean 定义对应多个对象实例。prototype 作用域的 bean 会导致在每次对该 bean 请求(将其注入到另一个 bean 中,或者以程序的方式调用容器的 getBean() 方法)时都会创建一个新的 bean 实例。

  3. request——每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效
    request只适用于Web程序,每一次 HTTP 请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,当请求结束后,该对象的生命周期即告结束。

java转发和重定向
https://www.cnblogs.com/duanwandao/p/9855229.html

物理分页和逻辑分页
https://www.cnblogs.com/tonghun/p/7122801.html
如果速度相同的话,优先选择物理分页,因为没必要把属于数据库端的压力加到应用端来

说说Cookie和Session的区别?

1、Cookie和Session都是会话技术,Cookie是运行在客户端,Session是运行在服务器端。

2、Cookie有大小限制以及浏览器在存cookie的个数也有限制,Session是没有大小限制和服务器的内存大小有关。

3、Cookie有安全隐患,通过拦截或本地文件找得到你的cookie后可以进行攻击。

4、Session是保存在服务器端上会存在一段时间才会消失,如果session过多会增加服务器的压力。

HTTP get和post请求的区别?
get和post是http与服务器端交互的两种不同方式。

1、数据安全性
GET请求提交的数据会在地址栏显示出来,而POST请求不会再地址栏显示出来。
POST提交:把提交的数据放置在是HTTP包的包体中。

get传输数据是通过URL请求,以field(字段)= value的形式,置于URL后,并用"?“连接,多个请求数据间用”&"连接,如http://127.0.0.1/Test/login.action?name=admin&password=admin,这个过程用户是可见的;
post传输数据通过Http的post机制,将字段与对应值封存在请求实体中发送给服务器,这个过程对用户是不可见的;

2、传输数据大小
HTTP GET请求由于浏览器对地址长度的限制而导致传输的数据有限制。而POST请求不会因为地址长度限制而导致传输数据限制。

java int占4个字节,32位

Java中的装箱和拆箱
装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。

一是包装器类对象具有很多可以调用的方法;
二是Java向面像对象语言的靠近。其实Java还不算是很纯的面向对象的语言。真正的面向对象,是没有基本数据类型的。它只有一种类型,就是对象;

MVC
MVC是Model-View-Controller的简称,即模型-视图-控制器。MVC是一种设计模式,它把应用程序分成三个核心模块:模型,视图,控制器,它们各自处理自己的任务。

模型(体现在下图中的POJO和数据库)是应用程序的主体部分,表示业务数据和业务逻辑。一个模型能为多个视图提供数据。由于应用于模型的代码只需要写一次就可以被多个视图重用,所以提高了代码的可重用性。
视图是用户看到并与之交互的界面,可以向用户显示相关的数据,也可以接收用户的输入,但是不进行任何实际的业务处理。
控制器接收请求,获取请求参数,调用DAO方法,决定用哪个模型组件去处理请求,然后决定调用哪个视图来显示模型处理返回的数据。

Exception和Error区别
Exception和Error继承Throwable类,在java中只有Throwable类型的实例才能被抛出(throw)或者捕获(catch),他是异常处理机制的基本类型。

Exception是程序正常运行过程中,可以预料的意外情况,可能并且应该被捕获,并进行处理。Error正常情况下不大可能出现的情况,绝大部分的Error都会导致程序状态不正常,不可恢复,既然是非正常情况,所以不便也不需要处理,例如OutOfMemoryError之类都是Error的子类

Exception分为检查型异常和运行时异常。检查型异常必须在源码中进行捕获处理,这是编译检查的一部分。除了RuntimeExceion及其子类之外的异常都是检查型异常。NullPointerException,ArrayIndexOfBoundException就是运行时异常,通常是可以通过编码避免的逻辑错误,

事务的四个特征
原子性、一致性、隔离性、持久性

数组和集合的区别:

1:长度的区别
数组的长度固定,集合的长度可变
2:内容不容
数组存储的是同一种类型的元素
集合可以存储不同类型的元素(但是一般我们不这样干…)
3:元素的数据类型
数组可以存储基本数据类型,也可以存储引用类型
集合只能存储引用类型(你存储的是简单的int,它会自动装箱成Integer)

Java ArrayList LinkedList
两者都是实现了List接口
ArrayList的底层数据结构是顺序存储结构
LinkedList是链式存储结构

springmvc spring事务和bean的作用域和生命周期
mysql 单例模式 工厂模式 代理模式
Redis 线程 排序算法的时间复杂度

冒泡 插入 快排 选择 二分查找 队列 栈 线性表和链式表 时间和空间复杂度

Sql注入
sql注入是一种将sql代码添加到输入参数中,传递到sql服务器解析并能正常执行的一种攻击手法

预编译的好处
大家平时都使用过JDBC中的PreparedStatement接口,它有预编译功能。什么是预编译功能呢?它有什么好处呢?

当客户发送一条SQL语句给服务器后,服务器总是需要校验SQL语句的语法格式是否正确,然后把SQL语句编译成可执行的函数,最后才是执行SQL语句。其中校验语法,和编译所花的时间可能比执行SQL语句花的时间还要多。

如果我们需要执行多次insert语句,但只是每次插入的值不同,MySQL服务器也是需要每次都去校验SQL语句的语法格式,以及编译,这就浪费了太多的时间。如果使用预编译功能,那么只对SQL语句进行一次语法校验和编译,所以效率要高。

数据库主键,外键是什么
辨识数据库表的唯一标识,每个数据库表只能有一个主键。
外键是相对于主键来说的,使表与表之间形成关联,保证数据的一致性,然后可以实现不同表的关联操作。

冒泡排序
冒泡排序是一种排序算法,比如有一组数字要从小到大进行排序,用冒泡排序的话就是将相邻两个元素进行比较,如果前一个元素的值比后一个元素大,就将这两个元素进行交换,这样遍历完一次后,最大的元素就会排在最后面,然后再去循环遍历这些元素,直到顺序是对的。

 public int[] bubbling(int[] array){
        for (int i = 0; i < array.length-1 ; i++) {
            boolean flag = false;
            for (int j = 0; j < array.length-1-i; j++) {
                if(array[j]>array[j+1]){
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j+1] = temp;
                    flag = true;
                }
            }
            if (flag==false){
                return array;
            }
        }
        return array;
    }

冒泡排序是一种用时间换空间的排序方法,最坏情况是把顺序的排列变成逆序,或者把逆序的数列变成顺序。在这种情况下,每一次比较都需要进行交换运算。举个例子来说,一个数列 5 4 3 2 1 进行冒泡升序排列

第一轮的两两比较,需要比较4次;得到 4 3 2 1 5
第二轮的两两比较,需要比较3次;得到 3 2 1 4 5
第三轮的两两比较,需要比较2次;得到 2 1 3 4 5
第四轮的两两比较,需要比较1次;得到 1 2 3 4 5

所以总的比较次数为 4 + 3 + 2 + 1 = 10次
对于n位的数列则有比较次数为 (n-1) + (n-2) + … + 1 = n * (n - 1) / 2,这就得到了最大的比较次数。
而O(N^2)表示的是复杂度的数量级。举个例子来说,如果n = 10000,那么 n(n-1)/2 = (n^2 - n) / 2 = (100000000 - 10000) / 2,相对10^8来说,10000小的可以忽略不计了,所以总计算次数约为0.5 * N2。用O(N2)就表示了其数量级(忽略前面系数0.5)。

综上所述,冒泡排序的时间复杂度为:O(n²)
算法稳定性:稳定
**ps:**算法稳定性指的是在一组数据中如果有元素的指相同,在进行排序后,这些元素的位置不变,这个算法就是稳定的。
比如:2,1,33 这组数据,在排序后,两个3的位置是不变的,就是稳定

插入排序

插入排序首先将一组数据分成两部分,分别是未排序和已排序。一般来说,将数组第一个元素定为已排序,其余的为未排序。之后循环遍历未排序的部分并逐个和排序好的相比较,插入对恰当的位置。

public int[] insertionSort(int[] array) {

        for (int i = 1; i <array.length ; i++) {
            for (int j = i-1; j >=0 ; j--) {
                if (array[i]<array[j]){
                    int temp = array[j];
                    array[j] = array[i];
                    array[i] = temp;
                }else {
                    break;
                }
            }
        }

        return array;
    }

时间复杂度:o(n^2)
稳定性:稳定

选择排序

选择排序首先将一组数据分成两部分,分别是未排序和已排序。一般来说,将数组第一个元素定为已排序,其余的为未排序。

 public int[] selectionSort(int[] array) {
        int max = 0;
        int index = 0;
        int len = array.length;
        for (int i = 0; i < len-1 ; i++) {
            for (int j = 0; j < len-i-1; j++) {
                max = array[j];
                index = j;
                if (array[j+1]>max){
                    max = array[j+1];
                    index = j+1;
                }
            }
            //加这个判断是假如数组的最后一位已经是最大值了,就不用进行交换,提高效率
            if (index!=len-1-i){
                System.out.println("ff");
                int temp = array[len - 1 - i];
                array[index] = temp;
                array[len - 1 - i] = max;
            }

        }
        return array;


    }

时间复杂度:o(n^2)
稳定性:稳定

接口
接口中的方法会被隐式的指定为 public abstract (只能是 public abstract,其他修饰符都会报错)。
接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误。)

在接口中,属性都是默认public static final修饰的,所以:
A(错误):不能用private修饰;
B(正确):在接口中,属性默认public static final,这三个关键字可以省略;
C(错误):没写属性的类型;
D(错误):final修饰的属性必须赋值;

代理模式
代理模式是一种设计模式,就是客户端想要访问目标对象,但是由于某些原因不方便直接访问,此时就需要借助代理对象来间接的访问目标对象。这样可以在不修改原目标对象的前提下,扩展目标对象的功能。
https://www.cnblogs.com/boboxing/p/8126046.html
https://blog.csdn.net/gv7lzb0y87u7c/article/details/93260673

class Demo{
    private static Demo demo = new Demo();
    static {
        System.out.println("A");
    }

    public Demo(){
        System.out.println("B");
    }
	//构造代码块,优先于构造方法
    {
        System.out.println("C");
    }

    }
    输出结果为:CBACB

java三大特性:
封装,继承,多态。如果是四个的话就还包括抽象

封装就是一个类把具体的实现细节隐藏起来,只提供外界能访问的接口。比如说要将属性封装起来,就可以提供set和get方法

封装的意义就在于将内部的实现细节隐藏起来,保证程序的安全性。这个也方便了开发者在调用时只需要直到参数的传递就行。

继承是类的扩展。就是子类可以继承父类的特征和行为,使得子类也可以访问父类的属性和方法

优点
通过继承将多个类中的相同的类容摘取出来变成一个新类,让其他类和当前的新类产生关系,达到代码复用性的目的

缺点
继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法;
降低代码的灵活性。子类必须拥有父类的属性和方法,让子类自由的世界中多了些约束;
增强了耦合性。当父类的常量、变量和方法被修改时,需要考虑子类的修改,而且在缺乏规范的环境下,这种修改可能带来非常糟糕的结果——大段的代码需要重构。

父类和子类有同样的属性a。
用father f = new child();
f.a 这样访问的是父类的值

子类的返回值类型和抛出的异常类型必须要小于等于父类的类型
要重写的方法的权限修饰符必须要大于等于父类方法的权限,不然就会报错

super
super是java的关键字之一,super是子类用来访问父类属性和方法的。
必须注意:访问父类的构造函数只能在子类的构造函数中访问,且必须是子类构造函数的第一行。可以在子类普通方法调用父类方法和属性,如super.say()
super.id,位置可以随意。但是不能在方法写super()

重写和重载:
同:重写和重载都是java多态的表现形式
重写:重写是父类和子类多态性,实质是子类重新定义父类的方法。其中方法名,参数个数,类型,返回值都要和父类一样。
访问修饰符的限制一定要大于等于被重写方法的访问修饰符;重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常,譬如父类方法声明了一个检查异常 IOException,在重写这个方法时就不能抛出 Exception,只能抛出 IOException 的子类异常,可以抛出非检查异常。

作用:当子类需要用父类内容时,并且子类需要定义自己特定的功能。就可以用重写。

重写是父类与子类之间多态性的表现,在运行时起作用(动态多态性,譬如实现动态绑定)
  而重载是一个类中多态性的表现,在编译时起作用(静态多态性,譬如实现静态绑定)

重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
作用:使用方法重载其实就是避免出现繁多的方法名,有些方法的功能是相似的,如果重新建立一个方法,重新取个方法名称,会降低程序可读性。

public class Demo {
    
public boolean equals( Demo other) {
        System.out.println("use Demo equals." );
        return true;    
}
    
public static void main(String[] args) {    
    Object o1 =new Demo ();
    Object o2 =new Demo ();        
    Demo o3 =new Demo ();
    Demo o4 =new Demo ();

   if (o1.equals(o2)) {
            System.out.println("o1 is equal with o2.");
        }

   if(o3.equals(o4)) {             
            System.out.println("o3 is equal with o4.");
        }
    }
}

use Demo equals.
o3 is equal with o4.

因为 Demo 类中的 public boolean equals(Demo other) 方法并没有重写 Object 类中的 public boolean equals(Object obj) 方法,原因是其违背了参数规则,其中一个是 Demo 类型而另一个是 Object 类型,因此这两个方法是重载关系(发生在编译时)而不是重写关系;故当调用 o1.equals(o2) 时,o2 是 Object 类型参数,实际上调用了 Object 类中的 public boolean equals(Object obj) 方法,因为在编译时 o1 和 o2 都是 Object 类型,而Object 类的 equals 方法是通过比较内存地址才返回 false;当调用 o3.equals(o4) 时,实际上调用了 Demo 类中的 equals(Demo other) 方法,因为在编译时 o3 和 o4 都是 Demo 类型的,所以才有上面的打印。

多态:
多态指的是同一个事物多种状态,就是说当一个操作在不同的对象时,会产生不同的结果。

多态的实现有两种:一种是编译时的多态,另外一种是运行时多态,编译时的多态是通过方法的重载实现的,而运行时多态是通过方法的重写实现的。
运行时的多态的实现,需要满足三个条件:1.继承(包括接口的实现)2.方法的重写 3.父类的引用指向子类对象

多态的作用
代码变的更加灵活,在调用方法时,根据传入参数的不同就可以执行不同的方法,从而得到想要的结果。

多态实际上是自动类型提升:

Animal a = new cat(); ( cat型自动提升为Animal型(向上转型,得按Animal对象进行操作),因此cat只能调用Anima类中的方法,cat中特有功能无法访问 )。如果还想用猫的特有功能,可以强制向下转型:Cat c = (Cat) a。向下转型是为了使用特有方法。如果两者不具备继承关系不能强制转换!(向上转型为了提高扩展性并限制特有方法,向下转型为了使用特定方法)。对于转型自始至终都是子类对象做着类型的变化:
尽管f是指向Zi()这个对象,但是实际运行依然是Zi()这个对象调用方法。因此会先去方法区Zi()这个空间中去找方法。若ZI()方法区中没有则会去找Fu()方法区,再去堆中找相对应的变量。若没有则在往上找,直到Object类。这其实就是运行时多态,即到底运行Fu()的方法还是Zi()的方法等到程序运行时再去确定。对于多态时的成员函数,总的来说分为三种情况:

1、父类有方法,子类有覆盖方法:编译通过,执行子类方法。

2、父类有方法,子类没覆盖方法:编译通过,执行父类方法(子类继承)。

3、父类没方法,子类有方法:编译失败,无法执行。

方法带final、static、private时是编译时多态,因为可以直接确定调用哪个方法。

class Fu {
    int num = 4;//没有这句会编译失败
}
class Zi extends Fu {
    int num = 5;
}
class Demo {
    public static void main(String[] args)  {
        Fu f = new Zi();
        System.out.println(f.num);
        Zi z = new Zi();
        System.out.println(z.num);
    }
}

总结:当子父类中出现同名的成员变量时,多态调用该变量时:
1、编译时期:参考的是引用型变量所属的类中是否有被调用的成员变量。没有,编译失败。
2、运行时期:也是调用引用型变量所属的类中的成员变量。
简单记:编译和运行都参考等号的左边。编译运行看左边。

多态性

向上转型:父类引用指向子类对象
Father father= new Child();
向下转型:父类引用转为子类引用,向下转型就是为了使用子类特有的方法
Father father= new Child();
Child child = (Child) father

向下转型例子

//描述动物类,并抽取共性eat方法
abstract class Animal {
    abstract void eat();
}

// 描述狗类,继承动物类,重写eat方法,增加lookHome方法
class Dog extends Animal {
    void eat() {
        System.out.println("啃骨头");
    }

    void lookHome() {
        System.out.println("看家");
    }
}

// 描述猫类,继承动物类,重写eat方法,增加catchMouse方法
class Cat extends Animal {
    void eat() {
        System.out.println("吃鱼");
    }

    void catchMouse() {
        System.out.println("抓老鼠");
    }
}

 class Test {
    public static void main(String[] args) {
        Animal a = new Dog(); //多态形式,创建一个狗对象
        a.eat(); // 调用对象中的方法,会执行狗类中的eat方法
        // a.lookHome();//使用Dog类特有的方法,需要向下转型,不能直接使用

        // 为了使用狗类的lookHome方法,需要向下转型
// 向下转型过程中,可能会发生类型转换的错误,即ClassCastException异常
        // 那么,在转之前需要做健壮性判断
        //比如Animal a = new Cat();
        //Dog d = (Dog) a; 
        // d.lookHome(); //报类型转换异常
        
        
        if( !(a instanceof Dog)){ // 判断当前对象是否是Dog类型
            System.out.println("类型不匹配,不能转换");
            return;
        }
        Dog d = (Dog) a; //向下转型
        d.lookHome();//调用狗类的lookHome方法
    }
}

mysql

LIMIT m,n : 表示从第m+1条开始,取n条数据;
LIMIT n : 表示从第0条开始,取n条数据,是limit(0,n)的缩写。
LIMIT n,-1 :表示从第n+1条开始,取到最后一条数据

js jquery ajax
jquery 是JS的一个框架
JS是网页的脚本语言
AJAX是指一种创建交互式网页应用的网页开发技术
ajax包括了xml css js 3个技术
jquery 中也集成了ajax 用他做不用考虑浏览器的不兼容性 封装了一些麻烦的东西

AJAX = 异步 JavaScript 和 XML。
AJAX 是一种异步传输的技术,用来做客户端和服务端之间数据的交互。
通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。
beforeSend
在实际项目开发中,提交表单时常常由于网络或者其原因,用户点击提交按钮误认为自己没有操作成功,进而会重复提交按钮操作次数,如果页面前端代码没有做一些相应的处理,通常会导致多条同样的数据插入数据库,导致脏数据的增加。要避免这种现象,在$.ajax请求中的beforeSend方法中把提交按钮禁用掉,等到Ajax请求执行完毕,在恢复按钮的可用状态。或者在提交数据时显示一个小圆圈在转也可以借助beforeSend实现

success 是ajax成功后后执行的函数。 complete 是ajax完成后执行的函数。 你还少说个error,error是ajax失败后执行的函数。

success就如同try
error就如同catch
complete则如同finally

ajax的done和always函数
done和always作用相同,及在一个延时函数或数组函数执行完毕执行。
不同的是,done是在当前函数执行成功后执行,异常时不会执行。always是在当前函数执行完毕后(不管成功与否)执行。

js可以操作cookie

A的ASCII码是65,a的ASCII码是97

集合
Set类:底下有HashSet, TreeSet, LinkHashSet
HashSet
元素唯一
元素无序的
线程不安全,若有多个线程同时操作同个HashSet时,需要用代码保证线程安全。
底层是hash表
哈希表依赖两个方法:hashCode()和equals()

HshSet是如何保证元素的唯一性的?
首先调用hashcode方法得到该元素的hashcode值,然后判断该值是否在集合中出现,如果没有,说明集合中不存在该元素,就将元素添加到集合,如果有,调用equals方法和哈希值相同的这些元素依次去比较,如果说有返回true的,那就说明有重复;如果说比较结果都为false,那就是不重复就添加。

LinkedHashSet:直接父类是 HashSet
元素唯一
元素不会进行排序
有序的
底层是链表和哈希表

TreeSet
元素唯一
元素会进行排序
底层是红黑树(是一种自平衡的二叉树)

List

ArrayList:
底层是数组
增删慢,查找快
支持动态扩容

LinkedList:
底层是链表
增删快,查找快

Map
hashmap
允许key/value为null,但是key只能有一个null
非线程安全,多个线程同时操作同一个HashMap实例所做的修改在线程间不同步
遍历时不保证任何顺序,跟元素插入顺序或者访问顺序无关
无序的
线程不安全

LinkedHashMap
底层是双向链表和哈希表
有序

String a = map.put(“星期”, “Mon”);
System.out.println(a); // 当给Map中添加元素,会返回key对应的原来的value值,若key没有对应的值,返回null

list和set的区别
list方法可以允许重复的对象,而set方法不允许重复对象

list是一个有序的容器,保持了每个元素的插入顺序。即输出顺序就是输入顺序,而set方法是无序容器,无法保证每个元素的存储顺序,

char和varchar的区别
char的长度是不可变的,而varchar的长度是可变的
定义一个char[10]和varchar[10],如果存进去的是‘abcd’,那么char所占的长度依然为10,除了字符‘abcd’外,后面跟六个空格,而varchar就立马把长度变为4了,取数据的时候,char类型的要用trim()去掉多余的空格,而varchar是不需要的,
char的存取数度还是要比varchar要快得多,因为其长度固定,方便程序的存储与查找;但是char也为此付出的是空间的代价,因为其长度固定,所以难免会有多余的空格占位符占据空间,可谓是以空间换取时间效率,而varchar是以空间效率为首位的。

sql查询成绩表中每一科成绩最高的分数以及这个学生的名字,学科名,

用的是自连接
https://www.cnblogs.com/weichao1996/articles/8519973.html

SELECT b.* FROM (SELECT `subject`,max(score) m from course GROUP BY `subject` ) t,course b WHERE t.subject = b.subject and t.m = b.score
CREATE TABLE `course` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(200) DEFAULT NULL,
  `subject` varchar(200) DEFAULT NULL,
  `score` int(200) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
int num = 0;
        for (int i = 0; i <=100 ; i++) {
            num = num++;
        }

        System.out.println(num); //0

Redis
string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)
应用场景:限流,比如一个接口限制用户一分钟内最多访问10次
发布和订阅

二叉树:
https://blog.csdn.net/cocoiehl/article/details/80959150
完全二叉树
定义:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
满二叉树一定是完全二叉树,反过来不一定成立

mybatis延迟加载
https://www.cnblogs.com/ashleyboy/p/9286814.html
mybatis关联查询
https://blog.csdn.net/qq_42373095/article/details/87387569

java中的switch选择结构可以使用数据类型的数据:
int ,char,byte,short,枚举,String: PS:对JDK版本有要求,必须为1.7及以上版本
boolean类型只能true,false

数组的声明方式
int a [][]= new int[5][5];
int[][] a1 = new int[5][5];
int[] a2[] = new int[5][];
int arr[][]={{22,15,32,20,18},{12,21,25}};

多线程 快排 二叉树,红黑树,集合的面试题
接口和抽象类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值