关键字
在java中有一定特殊含义的且全部小写的,就是关键字
标识符
在java中凡是可以自己起名的都可以算标识符。由26个英文字母大小写,0-9,_或$组成 数字不可以开头。不可以使用关键字和保留字,但能包含关键字和保留字。Java中严格区分大小写,长度无限制。标识符不能包含空格。
变量
在java中利用声明的方式将某个数据保存下来供程序使用,并且这个数据是可以根据自己需求发生改变的。
为什么要有数据类型存在
因为数据是有明确的类型划分的,为了确保变量保留的数据其类型的唯一性,要使用数据类型进行变量的修饰。
运算符
变量在运算时用到的符号就是运算符。
for循环的语法格式和执行过程
for(①初始化部分;②循环条件部分;④迭代部分){③循环体部分;}执行过程为①-②-③-④-②-③-④-②-③-④
break,continue,return区别
break:在循环中遇到break,直接结束当前整个循环.例如一个for循环原本从1输出到5,但是在等于2的时候break就会只能输出1,后面直接不输出。
continue:在循环中遇到continue,则结束当前这一次循环,继续执行下一次循环,比如在1到5的for循环 等于2的时候遇见,就直接执行结果为1 345
return:在方法中使用,遇到return时候是直接结束这个方法!不单是循环。
强制类型转换和自动类型转换的区别
强制类型转换就是从大范围的转到小范围的,会损失精度,要加变量类型的符号。自动类型转换就是小范围转到大范围,直接输入就行。
当对byte、short、char类型赋值时,如果没有超出当前数据类型取值范围,则是可以直接赋值的 。
当byte、short、char类型进行混合运算时,则先转为int类型,然后再进行计算 。
当多种类型进行混合运算时,结果为当前运算中取值范围大的类型 。
方法
注意事项:在Java中,方法是不支持嵌套的,只能编写在类中,或者编写在其它方法的外面。
方法的好处:1.使程序变得更简短而清晰。2.有利于程序维护。3.提高代码的复用性。4.一个方法编写好以后可以调用任意多次。
形参和实参
在编写方法时,未知的数称为形式参数,简称形参,比如:n就是形参
在调用方法时,给具体的值称为实际参数,简称实参
其实,也就是:实参的值赋给形参的变量名称,必须保证实参与形参的个数一致、类型一致、顺序一致
方法什么时候编写为带返回值类型的?
该方法只有一个结果,则就可以编写为带返回值类型的方法完成。将功能封装在方法里面的目的是,可以实现代码重用,简化代码。
方法重载的特点
在一个类中允许同时存在两个或者两个以上拥有相同名字的方法,且参数列表不同,与返回值类型无关,这样的方法就可以构成方法的重载(overload) 参数列表:参数的个数不同,参数的数据类型不同,参数类型的顺序不同(其中一个不同就行)。
JVM的5大模块
类加载子系统,运行时数据区,执行引擎,java本地接口。
运行数据区(jvm的内存)中有堆,栈,方法区(还有pc寄存器,本地方法栈,先说这几个)。
栈,主管Java程序的运行,它保存方法的局部变量、并参与方法的调用和返回。
在调用方法时,JVM会为该方法开辟一个栈帧,存储该方法里的参数,局部变量等等;每一个方法从调用直到执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
堆,此内存区域唯一的目的就是存放对象的实例,在虚拟机启动时创建,当执行new关键字时就会在jvm中的堆内存空间中开辟一段内存空间,用于存储创建好的对象。
方法区(Method Area)它用于存储已被虚拟机加载的class信息。类加载器将class文件加载到内存之后,将类的信息存储到方法区中。
记住一个结论:只要new了,就会创建一个对象并会在JVM的堆内存中新开辟一块堆内存空间存储该对象信息。也就意味着和原来的内存空间没有任何关系了。
封装的概念
封装就是隐藏类的内部信息(属性和方法),不允许外部程序直接访问,而是通过公有的方法才能完成访问(赋值方法get()和取值方法set()) ,如果封装一个方法(private)那么这个方法只能在本类中使用。
什么是构造方法
构造方法是一个特殊的方法,主要特殊点如下:
构造方法的名字与类的名字一致
它不声明返回值类型。(与声明为void不同)
不能被static、final、synchronized、abstract、native修饰,
不能有return语句返回值
构造方法注意事项
当一个类被创建时,则系统就会提供一个默认的无参数构造方法,也称之为隐士构造方法,直白一点说,就是当一个类中没有人为的编写构造方法时,则会存在一个默认无参数的构造方法 。但是,当在一个类中编写了有参数的构造方法,则系统就不会提供默认的无参的构造方法了。 注意 构造方法也构成方法的重载。
什么是JavaBean
JavaBean是一种Java语言写成的可重用组件。
所谓JavaBean,是指符合如下标准的Java类:类是公共的。有一个无参的公共的构造器 。有属性,且有对应的get、set方法。
this关键字
使用this关键字可以访问本类中的构造方法
当this后面小括号中没有参数时,则执行本类无参数的构造方法
当this后面小括号中有参数时,则执行本类相匹配的带参构造方法
this关键字的注意事项
可以在类的构造器中使用"this(形参列表)"的方式,调用本类中重载的其 它的构造器!
明确:构造器中不能通过"this(形参列表)"的方式调用自身构造器
如果一个类中声明了n个构造器,则最多有 n - 1个构造器中使用了 "this(形参列表)"
"this(形参列表)"必须声明在类的构造器的首行!
在类的一个构造器中,最多只能声明一个"this(形参列表)"。
静态变量和实例变量的区别
静态变量对于类而言在内存中只有一个,能被类的所有实例所共享。
实例变量对于类的每个实例都有一份,它们之间互不影响
当对象名中的值为null时,依然可以访问静态变量名,不会出现空指针异常,原因就是静态变量不属于某一个对象,而是当前这个类的所有对象都可以共享。
static关键字
被static修饰的类变量能被类的所有实例所共享。
在static方法内部只能访问类的static修饰的属性或方法,不能访问类的非static的结构
因为不需要实例就可以访问static方法,因此static方法内部不能有this。
static修饰的方法不能被重写 继承
一般在编写工具类中的工具方法时,会将该方法编写为静态方法,原因:使用类名.比较方便 。
一般只修饰变量和方法;
平常不可以修饰类,但是内部类却可以被static修饰。
static修饰成员变量:整个类的实例共享静态变量
static修饰方法:静态方法,只能够访问用static修饰的属性或方法,而非静态方法可以访问static修饰的方法或属性
被static修饰了的成员变量和方法能直接被类名调用。
static不能修饰局部变量,切记,不要搞混淆了,static平常就用来修饰成员变量和方法及块
UML类图
静态代码块和非静态代码块
基本数据类型修饰参数传递
当是基本数据类型时,在内存中存放的是真正的值
当是基本数据类型作为参数进行传递时,实参传递给形参的是真正的值,也就是:相当于复制一份。
当另一个方法中局部变量的值发生改变,不会对原来方法中局部变量的值更改,因为它们都是独立的,没有影响
引用数据类型修饰参数传递
当是引用数据类型时间在内存中存放的是地址
当引用数据类型作为参数进行传递时,实参传递给形参的是地址,也就是:实参与形参存放同一个地址,指向同一个对象,也就是说:当另一个方法中对象的属性值发生改变,对原来方法中对象的属性值有影响。
递归方法
递归方法:一个方法体内调用它自身。
方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执 行无须循环控制。
递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死 循环。
重写特点
方法重写只能发生在子父类中,方法重写以后,子类中重写的方法,返回值类型,参数名称,参数列表与父类中被重写的方法必须一致。
重载和重写的区别
修饰符的访问权限总结
方法重写中的访问权限说明
方法的重写也叫做方法覆盖override
Ø 重写的规则
Ø 不能缩小访问权限
Ø 返回值类型一致 或者 父类方法返回值类型的子类类型
Ø 方法名称必须一致
Ø 参数列表必须一致
super关键字
当子类中重写父类的方法时,如果再在子类的重写的方法体中调用父类中的该方法,就得用super 。
super使用域:只能在子类中使用。
当子类中重写父类的方法时,如果再在子类的方法体中调用父类中的方法,则只能使用super.方法。否则自己调用自己,就会出现死循环,没有意义(递归调用 )
this关键字和super关键字的区别
this关键字和super关键字都只能出现在第一行,如果子类构造方法中没有使用指定调用父类的哪一个构造方法时,则系统默认调用父类的无参构造方法,等价于编写super();
为什么super(…)和this(…)调用语句不能同时在一个构造器中出现?
思路:首先要明白this()与super()各自的功能,再谈两者同时出现在一个构造函数中时,为什么会报错。
首先是不安全,因为在构造函数中,会在第一行声super(),此时super()默认先调用父类的无参构造,或者super()调用有参构造,然后再完成子类特有属性的初始化。而在子类的构造函数中this()调用的是子类中的其他构造函数,其他构造函数中必然会有默认调用父类无参构造方法,或直接调用有参构造方法的构造函数,此时,同一个子类构造器中声明了两次父类构造函数,即父类初始化了两次,造成不安全的问题。
再者是失去了语句的意义,如果同时在子类构造方法中调用了两次同样的构造函数,编译器不通过。
单例设计模式
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对 某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
单例设计模式-饿汉式
单例设计模式-懒汉式
什么是设计模式?
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、 以及解决问题的思考方式。设计模式免去我们自己再思考和摸索。就像是经典 的棋谱,不同的棋局,我们用不同的棋谱。”套路” 。
多态
多态的语法格式:
父类类型 引用名 = new 子类()
Pet cat = 通过Cat来构建动物类对象-Pet pet= new Cat();
dog = 通过Dog来构建动物类对象-pet= new Dog()
多态的动态绑定技术:
两个类存在extends继承关系后,使用多态构建的对象去调用子类中重写的方法,那么调用的方法显示的虽然是父类的,但是输出的结果却是子类重写以后的。
注意:当构成多态时,引用名是父类类型,父类中编写的是公共的属性和公共的方法,因此该引用名只能访问父类中公共的属性和方法,但是优先访问子类对象中重写以后的方法
多态中的两种类型转换:
向上转型:
表现形式:当构成多态时,就是向上转型。
Pet cat = new Cat();
Pet dog = new Dog();
向上转型的体现:从右向右左看,是一个由子到父的过程
注意:
当前应用对象名称是父类类型,则只能访问父类中公共的属性和公共的方法,但是优先访问子类重写以后的方法。
多态的动态绑定技术:调用的方法父类的,但是输出的结果却是子类重写以后的。
向下转型:
基本数据类型:类型转换-自动(从小到大)-强制(从大到小) 数据类型范围大小
引用数据类型:类型转换-自动(从子类到父类 下-上->向上转型)-强制(从父类到子类 上-下->向下转型) 子,父类
表现形式:由父到子的过程
Pet cat = new Cat();
Cat newCat = (Cat)(cat);
instance of
结论:在进行向下转型之前,必须先判断,判断被转换的父类的引用与预期要转换的类型是否一致,一致就执行转换操作,反之不执行。
Pet cat = new Cat();
Cat newCat = (Cat)(cat);
Dog dog= (Dog)cat;//错误的
代码实操
当进行向下转型之前建议先判断,如果满足则再进行向下转型,使用instanceof关键字,避免出现
判断当前引用cat是否是Cat类型的,如果是返回true,执行类型转换操作,否则为false,不执行类型转换操作。
x instanceof A:检验x是否为类A的对象,返回值为boolean型。
要求x所属的类与类A必须是子类和父类的关系,否则编译错误。
如果x属于类A的子类B,x instanceof A值也为true。
包装类
public class Test03 { public static void main(String[] args) { Integer i1 = 789; //自动装箱 , java会根据int整数789创建一个Integer对象, 把这个对象的引用赋值给i1
int num = i1; //自动拆箱, 把i1引用的Integer对象的value属性值赋值给num
Integer i2 = 789; //根据789创建一个新的Integer对象 System.out.println(i1 == i2); //false
Integer i3 = 69;
Integer i4 = 69;
System.out.println(i3 == i4); //true
享元模式 :
Java认为-128~127范围内的整数使用最频繁, 所以这个范围内整数自动装箱后, 采用享元模式, 类似于String字符串字面量, 即i3与i4引用的是共享池中同一个value值为69的Integer对象 。
final关键字
抽象类
特点:1.抽象类使用abstract关键字区修饰类,其中abstract表示一种抽象.2.抽象类不能创建对象,可以通过子类创建,也就是:抽象类是多态的一种形式(多态中的向上转型)。3.抽象类中既可以存在普通方法,还可以存在抽象方法:抽象方法必须没有方法体。抽象方法必须在抽象类中。当子类继承抽象类时,子类必须重写抽象类中所有的抽象方法,否则子类也是抽象类。
模板方法设计模式
当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以 把不确定的部分暴露出去,让子类去实现。
接口
接口的本质就是将方法封装,与继承关系类似,接口与实现类之间存在多态性 。
代理设计模式
可以为其它对象提供一种代理以控制对这个对象的访问,屏蔽对真实角色的直接访问。
工厂设计模式
本质思想: 实例化对象,用工厂方法代替 new 操作。 将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实现类(实际要new的类)解耦。
Ø 简单工厂模式(也叫静态工厂模式):
用来生产同一等级结构中的任意产品。(对于增加新的产品,需要修改已有代码)
Ø 工厂方法模式:
用来生产同一等级结构中的固定产品。(支持增加任意产品,对于其它产品族的新增扩展性差)
Ø 抽象工厂模式:
用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)
简单工厂模式
简单工厂模式,从命名上就可以看出这个模式一定很简单。
它存在的目的很简单:
定义一个用于创建对象的工厂类。
调用者只要知道他要什么,从哪里拿,如何创建,不需要知道分工。多出了一个专门生产 Car 的实现类对象的工厂类。把调用者与创建者分离。
小结:
简单工厂模式也叫静态工厂模式,就是工厂类一般是使用静态方法,通过接收的参数的不同来返回不同的实例对象。
缺点:对于增加新产品,不修改代码的话,是无法扩展的。违反了开闭原则(对扩展开放;对修改封闭)
工厂方法模式
为了避免简单工厂模式的缺点,不完全满足 OCP(对扩展开放,对修改关闭)。工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个工厂类,
而工厂方法模式有一组实现了相同接口的工厂类。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。
Ø 总结:
简单工厂模式与工厂方法模式真正的避免了代码的改动了?没有。在简单工厂模式中,新产品的加入要修改工厂角色中的判断语句;
而在工厂方法模式中,要么将判断逻辑留在抽象工厂角色中,要么在客户程序中将具体工厂角色写死(就像上面的例子一样)。而且产品对象创建条件的改变必然会引起工厂角色的修改。
面对这种情况,Java 的反射机制与配置文件的巧妙结合突破了限制——这在 Spring中完美的体现了出来。
抽象工厂模式
抽象工厂模式和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。
抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象。而且使用抽象工厂模式还要满足一下条件:
1) 系统中有多个产品族。
但是当产品种类非常多时,就会出现大量的与之对应的工厂类,这不应该是我们所希望的。所以建议在这种情况下使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:
即
对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实现
如果产品树上涉及多个产品族,则可以使用抽象工厂模式
抽象类和接口的区别
相同点:
都不能创建对象,其实:抽象类和接口都是多态的一种形式
抽象类和接口中都可以编写抽象方法
子类或实现类都必须要重写抽象类或接口中的所有的抽象方法,否则子类或实现类就是抽象类
不同点:
抽象类
使用abstract关键字
抽象类中包含:普通类中包含的所有内容,也可以包含抽象方法
子类继承抽象类,并且是单继承
抽象类的出现就是为了统一标准,但是有单继承局限
接口
使用interface关键字
在JDK8.0中,接口包含:抽象方法(默认有public abstract)、公有静态常量(默认有public static final)、public static修饰的方法、public default修饰的方法
实现类实现接口,并且是多实现
接口的出现是为了统-标准,同时没有单继承局限
接口也弥补了Java单一继承的弱点,也就是类可以实现多个接口。
内部类
循环结构可以嵌套,选择结构可以嵌套,内部类的出现,让类和类之间也可以嵌套。
当一个类的定义出现在另一个类的类体中时,那么这个类叫做内部类,而这个类所在的类叫做外部类。
内部类能解决的问题
可让类和类之间的继承/实现更简化
让接口和抽象类也可以new
什么时候构建内部类
当一个类存在的价值仅仅是为某一个类单独服务时,那么就可以将这个类定义为所服务类中的内部类,这样可以隐藏该类的实现细节并且可以方便的访问外部类的私有成员而不再需要提供公有的get和set方法。
静态内部类(static修饰的内部类就叫静态内部类)
1、静态内部类能够直接被外部类给实例化,不需要使用外部类对象
2、静态内部类中可以声明静态方法和静态变量,但是非静态内部类中就不可以声明静态方法和静态变量
局部内部类(直接将一个类的定义放在方法体的内部)
1.局部内部类只能在该方法的内部使用。
2.局部内部类可以在方法体中直接创建对象。
3.局部内部类不能使用访问控制符和static关键字修饰符。
4.局部内部类可以使用外部方法的局部变量,但是必须是final的,当没有加final时,默认也是final的。(由于局部内部类是将该变量复制一份到内部使用的,担心在使用过程中局部内部类的外面的代码对该变量进行了修改,所以要用final修饰。)
特殊的局部内部类(匿名内部类)
// AnonymousInterfaceTest类中的test方法需要传入一个AnonymousInterface接口类型的对象 public class AnonymousInterfaceTest { public static void test(AnonymousInterface ai){ ai.show(); } public static void main(String[] args) { AnonymousInterfaceTest ait = new AnonymousInterfaceTest(); ait.test( new AnonymousInterface() { @Override public void show() { System.out.println("这是一个匿名内部类"); } }); } }
数组
数组的初始化有两种,静态初始化和动态初始化。
int [] arr={1,5,8,9} int[]arr=new int[4]
数组优缺点
优点:索引值是连续的 通过数组名称[引用]可直接访问数组中的元素,效率高
缺点:向数组中插入/删除元素,需要扩容, 复制/移动大量的元素, 效率低。 数组只适合遍历/修改,不适合插入/删除。
注意:静态数组一旦初始化,其长度将不能改变!
二分法查找算法
原理:每一次都去获取数组的中间索引所对应的元素,然后和要查找的元素进行比对,如果相同就返回索引如果不相同,就比较中间元素和要查找的元素的值:
1.如果中间元素的值大于要查找的元素,说明要查找的元素在左侧,那么就从左侧按照上述思想继续查询(忽略右侧数据),
2.如果中间元素的值小于要查找的元素,说明要查找的元素在右侧,那么就从右侧按照上述思想继续查询(忽略左侧数据
注意:二分法查找是要求数组已经排好序!
冒泡排序算法
选择排序
选择排序的思想:每次都是利用遍历把最小的一个元素放到最前面去,下一次的循环就是数组长度减一个。
核心代码如图
数组工具类Arrays
其实个人觉得 最核心的是元素的拷贝方法:copyof(T[],int newLength)
int [] yiYang=Arrays.copyOf(ints,ints.length); system.out.println(Arrays.toString(yiTang));
数组扩容
数组扩容的核心概念:其实就是定义一个更大的数组,把原来的元素复制到大的数组中,切记!还要把原来的数组名指向这个大的数组(也就是把这个大的数组的地址和原本数组的地址保持一致)
动态数组的插入和删除
插入的核心思想如图所示
删除思想:其实原本元素并没有删除,只是重新创建了一个新数组拷贝了除删除元素以外的原有元素,还把这个大的数组的地址和原本数组的地址保持一致。然后重新遍历了一下,本质还是数组拷贝。