文章目录
- 第一阶段:JavaSE
- 1、面向对象编程(基础)
- 1)面向过程和面向对象区别
- 2)类和对象的概述
- 3)类的属性和方法
- 4)创建对象内存分析
- 5)构造方法(Construtor)及其重载
- 6)对象类型的参数传递
- 7)this关键字详解
- 8)static关键字详解
- 9)局部代码块、构造代码块和静态代码块
- 10)package和import详解
- 11)JavaDoc生成API文档
- 12)递归
- 第五阶段:高级框架
- 1、mybatis
- 1)MyBatis概述
- 2)MyBatis入门配置
- 3)基本的CRUD操作
- 4)核心配置文件详解
- 5)Mapper.xml基础详解
- 6)模糊查询
- 7)分页的实现及插件PageHelper的使用
- 8)动态sql+sql片段的使用
- 9)一对多、多对一的关系处理
- 10)注解的使用
- 11)一级缓存和二级缓存说明及使用
- 12)Mybatis Log4j的使用
- 13)Mybatis slf4j的使用
- 14)Mybatis动态代理的使用
- 15)MyBatis Generator介绍
- 16)generatorConfig.xml讲解
- 17)MyBatis Generator序列化配置
- 18)MyBatis Generator生成toString()
- 19)MyBatis Generator的数据库设置
- 20)MyBatis Generator包设置
- 21)MyBatis Generator的表设置
- 22)基于MyBatis Generator的数据查询
- 23)基于MyBatis Generator的数据添加
- 24)基于MyBatis Generator的数据更新
- 25)基于MyBatis Generator的数据删除
第一阶段:JavaSE
1、面向对象编程(基础)
1)面向过程和面向对象区别
一、思想理念的不同
面向对象编程(Object-Oriented Programming,OOP)注重将问题分解为一组相互关联的对象,这些对象具有自己的属性和行为。OOP的核心思想是通过模拟真实世界的实体,以对象为中心进行设计和开发。对象之间通过消息传递进行通信和交互,实现系统功能的实现。
相比之下,面向过程编程(Procedural Programming,P)则更加关注问题的步骤和流程。它将问题分解为一系列的步骤或者函数,并按照特定的顺序执行。P过程性编程以算法为中心,强调问题的解决过程,将数据和功能分离,逐个处理步骤来实现程序的功能。
二、抽象程度的不同
面向对象编程通过封装、继承和多态等机制,可以将现实世界的复杂问题抽象成更简单、更易于理解的模型。它强调对象的概念,将数据和操作数据的方法封装在一起,以便更好地组织和管理代码。通过定义类和对象,OOP可以提供更高层次的抽象,使得代码的重用性和可维护性更强。
相反,面向过程编程的抽象程度较低。它将问题分解为一系列的步骤或函数,每个步骤都是按照特定的逻辑顺序执行的。P过程性编程更加直接和实际,处理问题的方式较为细节化。虽然可以使用函数来组织代码,但对于大型项目来说,代码的可读性和可维护性可能会受到挑战。
三、代码的复用性和可维护性不同
面向对象编程具有良好的代码复用性和可维护性。通过类的继承和多态等特性,可以将通用的行为和属性封装在父类中,子类可以继承和扩展这些特性。这种代码的组织方式使得代码结构清晰,易于理解和修改,提高了开发效率。
相比之下,面向过程编程的代码复用性和可维护性较差。由于函数和数据相分离的特点,代码的重用性较低。当需求发生变化时,可能需要修改多个函数,这会导致代码的可维护性下降。
四、团队协作和开发效率不同
面向对象编程在大型项目中具有良好的团队协作性。通过对象的封装和信息隐藏,不同的团队成员可以独立开发和测试各自的模块,减少了彼此之间的依赖。同时,OOP的抽象和封装特性可以提高代码的可读性和可维护性,进而提高开发效率。
相反,面向过程编程的团队协作性相对较差。由于函数和数据相分离的特点,不同的开发人员之间可能需要更多的沟通和协调,以确保代码的正确性和一致性。在大型项目中,代码的维护和扩展也相对困难,开发效率较低。
五、灵活性和可扩展性不同
面向对象编程具有较高的灵活性和可扩展性。由于对象之间的关系是通过消息传递实现的,可以在运行时动态地创建、销毁和修改对象。这种动态性使得系统能够更好地适应变化的需求,添加新功能或修改现有功能更加方便。
相对而言,面向过程编程的灵活性和可扩展性较低。由于代码的组织方式是基于函数和步骤的顺序执行,当需要添加新功能时,可能需要修改多个函数或步骤,可能会引发连锁反应,增加了代码的复杂性和风险。
六、封装和信息隐藏不同
面向对象编程强调封装和信息隐藏的概念。通过将数据和操作数据的方法封装在对象内部,对外部提供公共接口进行访问,实现了数据的隐藏和保护。这种封装性可以有效地防止数据被错误地修改,增强了代码的安全性和可靠性。
而面向过程编程的封装性较差,数据和功能之间的关系比较松散。数据通常被多个函数共享,可能会导致数据被错误地修改或误用,增加了代码出错的风险。
七、编程范式的应用领域不同
面向对象编程通常适用于大型软件系统的开发,例如企业级应用、图形界面程序等。OOP的思想和方法可以更好地应对复杂性和变化性,提供了更高层次的抽象和组织方式,便于团队协作和可维护性。
面向过程编程则更适用于较小规模、简单和直接的任务。例如编写一些简单的脚本、数据处理程序等。由于P过程性编程更注重问题的解决过程,适合于一步一步的逻辑操作。
综合考虑以上几个方面的区别,选择适合具体需求的编程范式是开发人员需要权衡的因素。面向对象编程强调代码的组织和抽象能力,适合大型项目和复杂系统的开发;而面向过程编程则更简单直接,适用于小规模任务和简单应用的开发。
延伸阅读1:面向对象程序设计的基本特征
面向对象程序设计(Object-Oriented Programming,OOP)具有以下基本特征:
一、封装(Encapsulation)
封装是指将数据和对数据的操作封装在一个单元内部,形成一个对象。对象对外部提供公共接口,隐藏了内部实现细节,通过接口访问对象的属性和方法。封装提供了信息隐藏和保护数据的能力,同时也提高了代码的可读性和可维护性。
二、继承(Inheritance)
继承是一种机制,允许一个对象(子类)继承另一个对象(父类)的属性和方法。通过继承,子类可以复用父类的代码,扩展或修改父类的功能。继承实现了代码的重用性和层次性,提供了面向对象编程的灵活性和可扩展性。
三、多态(Polymorphism)
多态是指同一个方法可以在不同的对象上产生不同的行为。通过多态,可以在父类引用的变量中存储子类对象,然后根据实际的对象类型来调用相应的方法。多态提供了代码的灵活性和可扩展性,能够处理不同类型的对象,提高了代码的可读性和可维护性。
四、抽象(Abstraction)
抽象是指从具体的事物中抽取出共同的特征和行为,形成一个抽象的类或接口。抽象类定义了一组相关的对象的通用特征,接口定义了一组操作的规范。抽象提供了问题领域的概念模型,使得程序设计更加高层次化和模块化。
这些基本特征共同构成了面向对象程序设计的基础。通过封装、继承、多态和抽象,面向对象编程可以提供更高层次的抽象和封装能力,实现代码的重用性、可维护性、可扩展性和灵活性。这种编程范式适用于大型软件系统的开发,能够提高开发效率和代码质量。
2)类和对象的概述
3)类的属性和方法
4)创建对象内存分析
5)构造方法(Construtor)及其重载
6)对象类型的参数传递
7)this关键字详解
8)static关键字详解
1、深度总结
引用一位网友的话,说的非常好,如果别人问你static的作用;如果你说静态修饰 类的属性 和 类的方法 别人认为你是合格的;如果是说 可以构成 静态代码块,那别人认为你还可以; 如果你说可以构成 静态内部类, 那别人认为你不错;如果你说了静态导包,那别人认为你很OK;
那我们就先在这几方面一一对static进行总结;然后说一些模糊的地方,以及一些面试中容易问道的地方;
1)static方法
static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。
但是要注意的是,虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法/变量的。举个简单的例子:
在上面的代码中,由于print2方法是独立于对象存在的,可以直接用过类名调用。假如说可以在静态方法中访问非静态方法/变量的话,那么如果在main方法中有下面一条语句:
MyObject.print2();
此时对象都没有,str2根本就不存在,所以就会产生矛盾了。同样对于方法也是一样,由于你无法预知在print1方法中是否访问了非静态成员变量,所以也禁止在静态成员方法中访问非静态成员方法。
而对于非静态成员方法,它访问静态成员方法/变量显然是毫无限制的。
因此,如果说想在不创建对象的情况下调用某个方法,就可以将这个方法设置为static。我们最常见的static方法就是main方法,至于为什么main方法必须是static的,现在就很清楚了。因为程序在执行main方法的时候没有创建任何对象,因此只有通过类名来访问。
2)static变量
static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本【存放在方法区】,它当且仅当在类初次加载时会被初始化【加final和不加final的static变量初始化的位置不一样】。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
static成员变量的初始化顺序按照定义的顺序进行初始化。
3)static代码块
static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次【根据class加载原理 每个类加载一次 使用双亲委托加载】。
初始化的顺序 静态代码块 > 构造代码块 > 构造函数
为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。下面看个例子:
isBornBoomer是用来这个人是否是1946-1964年出生的,而每次isBornBoomer被调用的时候,都会生成startDate和birthDate两个对象,造成了空间浪费,如果改成这样效率会更好,其实就是利用了静态代码块在内存中值加载一次的机制:
因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。
4)静态内部类
这个地方不单独写静态内部类,通过和普通的内部类对比来加深对静态内部类的理解:
为何要用内部类?
-
内部类一般只为其外部类使用;【供外部类使用说的很好 举例 hashmap集合中 有一个内部类 Entry 就是 转为为 hashmap 存储来使用】
-
内部类提供了某种进入外部类的窗户,内部类存在外部类的引用,所以内部类可以直接访问外部类的属性;
-
也是最吸引人的原因,每个内部类都能独立地继承一个接口,而无论外部类是否已经继承了某个接口。因此,内部类使多重继承的解决方案变得更加完整。
定义在一个类内部的类叫内部类,包含内部类的类称为外部类。内部类可以声明public、protected、private等访问限制,可以声明 为abstract的供其他内部类或外部类继承与扩展,或者声明为static、final的,也可以实现特定的接口。
外部类按常规的类访问方式(以对象的方式)使用内部 类,唯一的差别是外部类可以访问内部类的所有方法与属性,包括私有方法与属性,外部类访问内部类,需要创建对象访问;有一点需要注意,内部类不能访问外部类所在的局部变量,只能访问final修饰的局部变量。
举例: 在方法中 定义内部类 然后内部类 调用方法的的入参 则 入参必须是 final 修饰
在方法内定义内部类时,如果内部类调用了方法中的变量,那么该变量必须申明为final类型,百思不得其解,后来想到应该是生命周期的原因,因为方法内定义的变量是局部变量,离开该方法,变量就失去了作用,也就会自动被消除,而内部类却不会离开它所在方法就失去作用,它有更广的生命周期,下面通过一个实例加以说明:
(1)创建实例
OutClass.InnerClass obj = outClassInstance.new InnerClass(); //注意是外部类实例.new,内部类
AAA.StaticInner in = new AAA.StaticInner();//注意是外部类本身,静态内部类
(2)内部类中的this
内部类中的this与其他类一样是指的本身。创建内部类对象时,它会与创造它的外围对象有了某种联系,于是能访问外围类的所有成员,不需任何特殊条件,可理解为内部类链接到外部类。 用外部类创建内部类对象时,此内部类对象会秘密的捕获一个指向外部类的引用,于是,可以通过这个引用来访问外围类的成员。
(3)外部类访问内部类
内部类类似外部类的属性,因此访问内部类对象时总是需要一个创建好的外部类对象。外部类对象通过‘外部类名.this.xxx'的形式访问内部类的属性与方法。如:
System.out.println("Print in inner Outer.index=" + pouter.this.index);
System.out.println("Print in inner Inner.index=" + this.index);
(4)内部类向上转型
内部类也可以和普通类一样拥有向上转型的特性。将内部类向上转型为基类型,尤其是接口时,内部类就有了用武之地。如果内部类是private的,只可以被它的外部类问,从而完全隐藏实现的细节。
(5)方法内的类
方法内创建的类(注意方法中也能定义类),不能加访问修饰符。另外,方法内部的类也不是在调用方法时才会创建的,它们一样也被事先编译了。
(6)静态内部类
定义静态内部类:在定义内部类的时候,可以在其前面加上一个权限修饰符static。此时这个内部类就变为了静态内部类。
通常称为嵌套类,当内部类是static时,意味着:
[1]要创建嵌套类的对象,并不需要其外围类的对象;
[2]不能从嵌套类的对象中访问非静态的外围类对象(不能够从静态内部类的对象中访问外部类的非静态成员);
嵌 套类与普通的内部类还有一个区别:普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段, 也不能包含嵌套类。但是在嵌套类里可以包含所有这些东西。也就是说,在非静态内部类中不可以声明静态成员,只有将某个内部类修饰为静态类,然后才能够在这 个类中定义静态的成员变量与成员方法。
另外,在创建静态内部类时不需要将静态内部类的实例绑定在外部类的实例上。普通非静态内部类的 对象是依附在外部类对象之中的,要在一个外部类中定义一个静态的内部类,不需要利用关键字new来创建内部类的实例。静态类和方法只属于类本身,并不属于 该类的对象,更不属于其他外部类的对象。
(7)内部类标识符
每个类会产生一个.class文件,文件名即为类名。同样,内部类也会产生这么一个.class文件,但是它的名称却不是内部类的类名,而是有着严格的限制:外围类的名字,加上$,再加上内部类名字。
代码具体:
public class OutClassTest {static int a;int b;public static void test() {System.out.println("outer class static function");}public static void main(String[] args) {// new一个外部类OutClassTest oc1 = new OutClassTest();// 通过外部类的对象new一个非静态的内部类OutClassTest.InnerClass no_static_inner = oc1.new InnerClass();// 调用非静态内部类的方法System.out.println(no_static_inner.getKey());// 调用静态内部类的静态变量System.out.println(OutClassTest.InnerStaticClass.static_value);// 不依赖于外部类实例,直接实例化内部静态类OutClassTest.InnerStaticClass inner = new OutClassTest.InnerStaticClass();// 调用静态内部类的非静态方法System.out.println(inner.getValue());// 调用内部静态类的静态方法System.out.println(OutClassTest.InnerStaticClass.getMessage());}private class InnerClass {// 只有在静态内部类中才能够声明或定义静态成员// private static String tt = "0";private int flag = 0;public InnerClass() {// 三.非静态内部类的非静态成员可以访问外部类的非静态变量和静态变量System.out.println("InnerClass create a:" + a);System.out.println("InnerClass create b:" + b);System.out.println("InnerClass create flag:" + flag);//System.out.println("InnerClass call outer static function");// 调用外部类的静态方法test();}public String getKey() {return "no-static-inner";}}private static class InnerStaticClass {// 静态内部类可以有静态成员,而非静态内部类则不能有静态成员。private static String static_value = "0";private int flag = 0;public InnerStaticClass() {System.out.println("InnerClass create a:" + a);// 静态内部类不能够访问外部类的非静态成员// System.out.println("InnerClass create b:" + b);System.out.println("InnerStaticClass flag is " + flag);System.out.println("InnerStaticClass tt is " + static_value);}public int getValue() {// 静态内部类访问外部类的静态方法test();return 1;}public static String getMessage() {return "static-inner";}}public OutClassTest() {// new一个非静态的内部类InnerClass ic = new InnerClass();System.out.println("OuterClass create");}}
4)静态导包
静态导包就是java包的静态导入,用import static代替import静态导入包是JDK1.5中的新特性。
一般我们导入一个类都用 import com……ClassName;而静态导入是这样:import static com……ClassName.;这里的多了个static,还有就是类名ClassName后面多了个. ,意思是导入这个类里的静态方法。当然,也可以只导入某个静态方法,只要把 .* 换成静态方法名就行了。然后在这个类中,就可以直接用方法名调用静态方法,而不必用ClassName.方法名 的方式来调用。
好处:这种方法的好处就是可以简化一些操作,例如打印操作System.out.println(…);就可以将其写入一个静态方法print(…),在使用时直接print(…)就可以了。但是这种方法建议在有很多重复调用的时候使用,如果仅有一到两次调用,不如直接写来的方便
example:
在Java 5中,import语句得到了增强,以便提供甚至更加强大的减少击键次数功能,虽然一些人争议说这是以可读性为代价的。这种新的特性成为静态导入。当你想使用static成员时,可以使用静态导入(在API中的类和你自己的类上,都可以使用该特性)。下面是静态导入前后的代码实例:
在静态导入之前:
public class TestStatic {public static void main(String[] args) {System.out.println(Integer.MAX_VALUE);System.out.println(Integer.toHexString(42));}}
在静态导入之后:
import static java.lang.System.out;import static java.lang.Integer.*;public class TestStaticImport {public static void main(String[] args) {out.println(MAX_VALUE);out.println(toHexString(42));}}
让我们看一下使用静态导入特性的代码中将发生什么:
1、虽然该特性通常称为“静态导入”,但语法必须是import static,后面跟你想导入的static成员的完全限定名称,或者通配符。在本例中,我们在System类的out对象上进行静态导入。
2、在本例中,我们可能想使用java.lang.Integer类的几个static成员。该静态导入语句使用通配符来表达“我想在此类中的所有静态成员上进行静态导入”。
3、现在我们终于看到静态导入特性的好处!我们不必在System.out.println中键入System。太好了!另外,我们不必在Integer.MAX_VALUE中键入Integer。因此,在这行代码中,我们能够将快捷方式用于静态方法和一个常量。
4、最后,我们进行更多的快捷操作,这次针对Integer类的方法。
关于该特性,我们已经有点儿讽刺意味儿了,但不仅我们是这样的。我们不认为节省少量的击键次数会让代码
难于阅读一点,但许多开发人员要求将它添加到语言中。
下面是使用静态导入的几条原则:
你必须说import static, 不能说static import。
提防含糊不清的命名static成员。例如,如果你对Integer类和Long类执行了静态导入,引用MAX_VALUE将导致一个编译器错误,因为Integer和Long都有一个MAX_VALUE常量,并且Java不会知道你在引用哪个MAX_VALUE。
你可以在static对象引用、常量(记住,它们是static 或final)和static方法上进行静态导入。
二.static关键字的误区
1.static关键字会改变类中成员的访问权限吗?
有些初学的朋友会将java中的static与C/C++中的static关键字的功能混淆了。在这里只需要记住一点:与C/C++中的static不同,Java中的static关键字不会影响到变量或者方法的作用域。在Java中能够影响到访问权限的只有private、public、protected(包括包访问权限)这几个关键字。看下面的例子就明白了:
2.能通过this访问静态成员变量吗?
虽然对于静态方法来说没有this,那么在非静态方法中能够通过this访问静态成员变量吗?先看下面的一个例子,这段代码输出的结果是什么?
public class Main { static int value = 33;public static void main(String[] args) throws Exception{new Main().printValue();}private void printValue(){int value = 3;System.out.println(this.value);}
输出
这里面主要考察队this和static的理解。this代表什么?this代表当前对象,那么通过new Main()来调用printValue的话,当前对象就是通过new Main()生成的对象。而static变量是被对象所享有的,因此在printValue中的this.value的值毫无疑问是33。在printValue方法内部的value是局部变量,根本不可能与this关联,所以输出结果是33。在这里永远要记住一点:静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)。
3.static能作用于局部变量么?
在C/C++中static是可以作用域局部变量的,但是在Java中切记:static是不允许用来修饰局部变量。不要问为什么,这是Java语法的规定。
三.常见的笔试面试题
下面列举一些面试笔试中经常遇到的关于static关键字的题目,仅供参考,如有补充欢迎下方留言。
1.下面这段代码的输出结果是什么?
public class Test extends Base{static{System.out.println("test static");}public Test(){System.out.println("test constructor");}public static void main(String[] args) {new Test();}
}class Base{static{System.out.println("base static");}public Base(){System.out.println("base constructor");}
}
至于为什么是这个结果,我们先不讨论,先来想一下这段代码具体的执行过程,在执行开始,先要寻找到main方法,因为main方法是程序的入口,但是在执行main方法之前,必须先加载Test类,而在加载Test类的时候发现Test类继承自Base类,因此会转去先加载Base类,在加载Base类的时候,发现有static块,便执行了static块。在Base类加载完成之后,便继续加载Test类,然后发现Test类中也有static块,便执行static块。在加载完所需的类之后,便开始执行main方法。在main方法中执行new Test()的时候会先调用父类的构造器,然后再调用自身的构造器。因此,便出现了上面的输出结果。
2.这段代码的输出结果是什么?
public class Test {Person person = new Person("Test");static{System.out.println("test static");}public Test() {System.out.println("test constructor");}public static void main(String[] args) {new MyClass();}
}class Person{static{System.out.println("person static");}public Person(String str) {System.out.println("person "+str);}
}class MyClass extends Test {Person person = new Person("MyClass");static{System.out.println("myclass static");}public MyClass() {System.out.println("myclass constructor");}
}
类似地,我们还是来想一下这段代码的具体执行过程。首先加载Test类,因此会执行Test类中的static块。接着执行new MyClass(),而MyClass类还没有被加载,因此需要加载MyClass类。在加载MyClass类的时候,发现MyClass类继承自Test类,但是由于Test类已经被加载了,所以只需要加载MyClass类,那么就会执行MyClass类的中的static块。在加载完之后,就通过构造器来生成对象。而在生成对象的时候,必须先初始化父类的成员变量,因此会执行Test中的Person person = new Person(),而Person类还没有被加载过,因此会先加载Person类并执行Person类中的static块,接着执行父类的构造器,完成了父类的初始化,然后就来初始化自身了,因此会接着执行MyClass中的Person person = new Person(),最后执行MyClass的构造器。
3.这段代码的输出结果是什么?
public class Test {static{System.out.println("test static 1");}public static void main(String[] args) {}static{System.out.println("test static 2");}
}
9)局部代码块、构造代码块和静态代码块
10)package和import详解
11)JavaDoc生成API文档
12)递归
第五阶段:高级框架
1、mybatis
1)MyBatis概述
2)MyBatis入门配置
3)基本的CRUD操作
4)核心配置文件详解
5)Mapper.xml基础详解
6)模糊查询
7)分页的实现及插件PageHelper的使用
8)动态sql+sql片段的使用
9)一对多、多对一的关系处理
10)注解的使用
11)一级缓存和二级缓存说明及使用
12)Mybatis Log4j的使用
13)Mybatis slf4j的使用
14)Mybatis动态代理的使用
15)MyBatis Generator介绍
16)generatorConfig.xml讲解
17)MyBatis Generator序列化配置
18)MyBatis Generator生成toString()
19)MyBatis Generator的数据库设置
20)MyBatis Generator包设置
21)MyBatis Generator的表设置
22)基于MyBatis Generator的数据查询
23)基于MyBatis Generator的数据添加
24)基于MyBatis Generator的数据更新
25)基于MyBatis Generator的数据删除