Java基础
命名
参数:开头小写并且不以数字开头由字母,数字,和$组成;驼峰命名法。
方法:开头小写并且不以数字开头;由字母,数字,_和$组成;驼峰命名法。
类:开头大写并且不以数字开头;由字母,数字,和$组成;驼峰命名法。
包:由小写单词组成;公司名称.开发组名称.项目名称.xxx。
方法的完整格式:
访问权限{public|缺省|protected|private}
final [synchronized]
返回值类型|void
方法名(参数列表)
[throws Exception]{
[return {返回值|返回调用处}];
}
注:返回调用处:
out :for
in:for
break in;
break out;
构造方法:构造函数的第一条语句必须是超类构造函数的调用语句
set方法:①xxXx setXxXx;② xXXX setxXXX
每个类中的每个参数都有set,get方法
java
com
cnsunet -- 公司名称
common ---公共部分baseDao等
db ---各个模块使用的数据库名称
persistence ---dao
presentation ---action,过滤器
scheduling ---定时任务
util ---工具类
entity ---实体类
enumeration ---枚举
pushManager ---消息推送
reporter ---报表导出
communication ---串口通讯
resultTypes ---重写velocityresult
xmlentity ---解码引擎实体类
resources
spring ---spring配置文件
struts2 ---struts2配置文件
velocity ---velocity配置文件
app.properties,struts.xml等文件
resources_release ---发布到服务器的配置文件,与resources类似,需注意配置的文件路径
运算符
运算符 | 用途 |
---|---|
/ | 取整 |
% | 取余 |
x++ | 下行再加 |
++x | 本行就加 |
&& | 与 |
& | 短路与 |
|| | 或 |
| | 短路或 |
boolean?true就是此结果:false就是此结果 | 三目运算符 |
二进制位操作
算术位运算:
与:& ; &=
或:| ; |=
非: ~ 因为是一元操作符,所以不可与=联用
异或:^ ;^=
移位运算:
算术左移: <<
算术右移: >>
控制语句
判断语句
if(表达式){
}else{
}
switch(参数){
case 值1: break;
case 值1: break;
default : ;
}
注:
1)参数可支持的数据类型:byte,short,int,char,string。
2)值只能是字符或者常量值。
循环语句
while(循环条件){
先判断再进入
}
do{
先进入再判断
}while(循环条件);
for(赋值初值;循环条件;赋值加减值){
}
for(数据类型 变量 : 参数){
}
注:
1)for与foreach性能比较:循环数组结构的数据时用for循环;当循环链表结构的数据时用foreach循环。
2)中断循环:break强制结束循环;continue直接进入到下一次循环。break与continue都只能跳出离他最近的循环。
3)
数据类型
基本数据类型(值传递)
类型 | 名称 | 长度(字节) | 注意事项 | 包装类 |
---|---|---|---|---|
byte | 字节 | 1 | -128~127 | Byte |
char | 字符 | 2 | Character | |
short | 短整型 | 2 | Short | |
int | 整型 | 4 | Integer | |
long | 长整型 | 8 | 数值后加L | Long |
float | 单精度浮点数 | 4 | 数值后加F | Float |
double | 双精度浮点数 | 8 | Double | |
boolean | 布尔值 | true/false | Boolean |
注:
1)1字节=8比特位
2)小精度到大精度自动转换。byte->short->int->long->float->double
3)大精度到小精度强制转换。(小精度类型)变量
4)int<ASCII码转换>char
引用数据类型(地址传递)
类型 | 名称 |
---|---|
String | 字符串 |
Calss | 类 |
Interface | 接口 |
Array | 数组 |
Annotation | 注解 |
栈stack | 堆heap | |
---|---|---|
基本数据类型 | √ | |
引用数据类型 | √对象名 | √new |
java参数传递:
1)值传递。不会改变值
2)引用传递。将堆内存空间的使用权交给多个栈空间对象,传内存地址值。
==比较地址,equals()比较内容,
hashcode与equals方法
compareTo与equals方法
类与对象
类:对象的集合(具有相同属性和相似行为)
对象:类的实例。(类是抽象的,对象是具体的)
类的成员:属性与方法
类的成员:静态成员(static声明)与实例成员(无static声明)。
四种创建对象的方法:
1、用new语句创建对象。
类 对象名 = new 类();
声明 = 实例化
1)对象名保存到栈内存中。
2)对象实体内容保存在堆内存中,通过new关键字分配堆内存空间。
3)声明可以不要,成为匿名对象(只开辟堆内存空间,不存在栈的引用)。
4)实例必须要,对象使用前必须要实例化。
2、调用对象的clone方法。
MyObject obj =new MyObject();
MyObject objs= obj.clone();
使用clone方法克隆一个对象的步骤:
1)被克隆的类要实现Cloneable接口;
2)被克隆的类要重写clone方法;
3、运行反射手段,使用Class.forName()
MyObject object =(MyObject)Class.forName("subin.rnd.MyObject").newInstance();
4、运用反序列化手段,调用java.io.ObjectInputStream对象的readObject()方法。
static
static静态的作用:在没有创建对象的情况下进行调用变量,方法,类。
修饰 | 变为 | 注意事项 | 用途 |
---|---|---|---|
内部类 | 静态内部类 | static class{} | |
成员方法 | 类方法/静态方法 | 类方法不能被重写覆盖 静态方法中不可以使用this或者super关键字 可以直接 ClassName.method()调用,无需对象.method()调用。 static修饰的方法不能调用非static方法。非static方法能调用static修饰的方法。原因是程序中所有的属性和方法必须在对象开辟堆内存之后才可以调用,而static方法在对象未被实例化时就可以被类调用。 | |
成员变量 | 全局属性/类变量/静态变量 | 静态变量数据存储在方法区(共享数据区)的静态区,能够被所有对象共享,所以也叫对象的共享数据。 可以直接ClassName.属性调用,无需对象.属性调用。 | 在多线程中通过static属性进行自动编名操作。 |
代码块 | 静态代码块 | static{} 优于主方法执行 | 驱动的安装 |
代码块
代码块 | 格式 |
---|---|
普通代码块 | method(){ { 普通代码块 } } |
构造块 | class{ { 构造块 } } |
静态代码块 | static{} |
JVM类加载器
执行前提:由构造方法引发类代码的加载。
执行顺序:
JVM类加载器 | ||
---|---|---|
前 | 静态块 | |
时 | 构造块 | 实例化几个对象就执行几次 |
后 | 构造方法 | 实例化几个对象就执行几次 |
内部类
可以方便的访问外部类中的私有属性。
意义及应用场合:
1)内部类对外不可见。
2)外部类的成员数据无论使用何种修饰符,静态与否,对内部类均可见。
3)借用内部类可以实现多重继承。每个内部类都能独立的继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口)的实现,对内部类都没有影响。
/** 类中定义内部类
* static定义的内部类不能访问非static的外部属性。
*/
//成员内部类。只存在实例成员,访问外部类实例字段与静态字段
class ClassName{}
//静态内部类
static class ClassName{}
/** 方法中定义内部类
* 方法中的参数要想被内部类访问到,必须变为常量,即加上final关键字。
*/
public void method(){
//局部类
class ClassName{
void show(){
//局部类在访问局部变量时,局部变量必须声明为final类型
System.out.println(isOn);
}
}
new ClassName().show();
//匿名内部类
new ClassNameInterface(){
//方式一:直接New出外部的接口或者类,但外部接口或抽象类如果有多个方法,那么应该先实例化出这个子类再调用其方法
@Override
public void showsInterface() {
System.out.println("重写了外部接口或者抽象类的方法");
}
}.showsInterface();
new Object(){
//方式二:直接new出的子类是可以调用其中的方法的
public void shows(){
System.out.println("直接new出的子类是可以调用其中的方法的");
};
}.shows();
Object obj = new Object(){
//方式三:不直接new出的子类因为指向了父类的引用所以不能调用子类的方法
public void shows(){
System.out.println("不直接new出的子类因为指向了父类的引用所以不能调用子类的方法");
};
};
obj.shows();
}
/*
* 内部类及匿名内部类的用法实例
* 1.在非静态的内部类中,如果定义一个static成员变量,那么必须添加final关键字才可以
* 2.在成员方法内 定义一个局部类,局部类在访问局部变量时,局部变量必须声明为final类型
* 3.内部类可以定义为抽象类,可以使成员变量继承抽象类
* 4.匿名内部类的使用就是直接New出外部的接口或者类,但外部接口或抽象类如果有多个方法
* 那么应该先实例化出这个子类再调用其方法
*/
public class InnerClass {
public static void main(String[] args) {
//new 一台Pc 尝试访问内部的非静态HardDisk类
Computer pc = new Computer();
//访问hardDisk的run()方法
pc.hardDisk.run();//硬盘正在运行啊!
//在非静态的内部类中,如果定义一个static成员变量,那么必须添加final关键字才可以
System.out.println(Computer.HardDisk.size);
//直接new 一个PC的harddisk 通过new 外部类().new 内部类()的方式调用
Computer.HardDisk hardDisk = new Computer().new HardDisk();
hardDisk.run();//硬盘正在运行啊!
//直接new 一个 静态的内部类 Motherboard的非静态方法run()
Computer.Motherboard board = new Computer.Motherboard();
board.run();//主板正在运行啊!
//直接访问静态内部类Motherboard的静态方法listen()
Computer.Motherboard.listen();//主板正在监控温度!
//静态方法访问主类的成员变量时候,该变量必须声明为静态才可以访问
Computer.Motherboard.usb();//鼠标已经连接好主板了!
board.show();
//在成员方法内 定义一个局部类,局部类在访问局部变量时,局部变量必须声明为final类型
//因为成员方法在调用完成后出栈,局部变量同样会销毁,但是new出的局部内部类不会被销毁,所以必须声明为final
pc.reset();
}
}
/**
* 建立一个显卡抽象类
*/
abstract class GraphicsInterface{
public abstract void useGraphics();
}
/**
* 定义电脑类
*/
class Computer{
//键盘
Keybord keybord;
//鼠标
static Mouse mouse;
//硬盘
HardDisk hardDisk;
//主板
Motherboard motherboard;
public Computer() {
this.keybord = new Keybord();
this.mouse = new Mouse();
this.hardDisk = new HardDisk();
this.motherboard = new Motherboard();
}
/**成员内部类*/
class HardDisk{
//在成员内部类中,如果定义一个static成员变量,那么必须添加final关键字才可以
static final String size = "1TB";
//定义的普通成员变量
int revolutions = 7200;
public void run(){
System.out.println("硬盘正在运行啊!");
}
}
/**静态内部类*/
static class Motherboard{
String type = "ATX" ;
public void run(){
System.out.println("主板正在运行啊!");
}
public static void listen(){
System.out.println("主板正在监控温度!");
}
public static void usb(){
System.out.println(mouse.name+"已经连接好主板了!");
}
public void show(){
System.out.println("主板是"+type+"型的!");
}
}
public void reset(){
final boolean isOn = true;
/**局部类*/
class screen{
void show(){
//局部类在访问局部变量时,局部变量必须声明为final类型
System.out.println(isOn);
}
}
new screen().show();
/**匿名内部类*/
new GraphicsInterface(){
//方式一:直接New出外部的接口或者类,但外部接口或抽象类如果有多个方法,那么应该先实例化出这个子类再调用其方法
@Override
public void useGraphics() {
System.out.println("重写了外部接口或者抽象类的方法");
}
}.useGraphics();
new Object(){
//方式二:直接new出的子类是可以调用其中的方法的
public void shows(){
System.out.println("直接new出的子类是可以调用其中的方法的");
};
}.shows();
Object obj = new Object(){
//方式三:不直接new出的子类因为指向了父类的引用所以不能调用子类的方法
public void shows(){
System.out.println("不直接new出的子类因为指向了父类的引用所以不能调用子类的方法");
};
};
// obj.shows();
}
}
/*
* 鼠标
*/
class Keybord{}
/*
* 键盘
*/
class Mouse{
String name="鼠标";
}
代码块
/**
代码块
静态构造块:static修饰。优于主方法的执行,用途:驱动的安装。
构造块:类中
普通代码块:方法中
程序运行结果:静态构造块->构造块->构造方法->普通代码块
产生原因:JVM类加载器
执行前提:由构造方法引发类代码的加载
执行顺序:
静态块 类加载器前
构造块 类加载器时。实例化几个对象就执行几次
构造方法 类加载器后。实例化几个对象就执行几次
*/
public class Demo {
//静态代码块
static {
System.out.println("静态构造块");
}
//构造块
{
System.out.println("构造块");
}
public void code(){
//普通代码块
{
System.out.println("普通代码块");
}
}
//构造方法
public Demo(){
System.out.println("构造方法");
}
public static void main(String[] args){
Demo demo=new Demo();
demo.code();
}
}
OO面向对象
OO(Object oriented)面向对象。它包括有OOA面向对象的分析,OOD面向对象的设计,OOP面向对象的实现。
三大特性
封装
外部不可见,只能在类的内部被调用。
访问修饰符 | 本类 | 本包 | 异包子类 | 异包非子类 |
---|---|---|---|---|
public公开的 | √ | √ | √ | √ |
protected受保护的 | √ | √ | √ | |
default缺省-空 | √ | √ | ||
private私有的 | √ |
注:
1)属性必须进行封装,通过get,set去获取设置值,可以保护不被外部类轻易的访问与修改,并且还可以验证属性值的正确性。
2)方法被封装后,外部可能不能直接调用此方法。
解决方案:
1)在此封装方法的类中,产生本类的静态实例对象。
2)自定义静态方法返回此对象。
3)外部通过 className.staticMethod 得到此对象,再用此对象在外部调用被封装的方法。
继承extends
子类通过继承父类,获得父类中可见成员,并扩展自己的新成员。通俗的讲法是,当两个类具有相同的属性或方法时,把相同部分的成员提取出来放到一个类中作为父类,然后这两个类去继承这个父类,这就是继承。
优点:因为方法重写,提高了代码的复用性。
缺点:首先耦合性高,其次单继承体系使子类不可继承其它类。
抽象abstract与接口interface
//普通方法
修饰符 Type method(){};
/**抽象方法
1)无方法体。只有方法的概念,没有方法的具体实现。
2)static final 修饰的方法不能被抽象。
*/
修饰符 abstract Type method(){};
//普通类
修饰符 Class ClassName{};
/**抽象类
1:如果一个类中存在抽象方法,那么这个类叫抽象类。
2:父类为抽象类,有抽象方法,子类中同名方法叫对抽象方法的实现,不叫重写。
3:抽象类不能直接创建对象(即不能直接new),需要通过向上转型去创建。
4:抽象类中不一定存在抽象方法。
5:抽象类中可以存在普通类的所有成员。
6:如果一个普通类继承了抽象类,那么这个类应该将所有父类的抽象方法全部实现。
7:抽象类一般用来做父类。
*/
修饰符 abstract Class ClassName{};
/**接口:抽象类中的方法都是抽象方法。
1:接口中可以出现的成员
1)抽象方法
2)静态常量final static Type NAME;
3)静态内部类static{}
2:如果一个普通类实现了接口,那么有义务去实现接口中的抽象方法。如果不想去实现接口中的抽象方法,那么让这个类变成抽象类。
3:接口可以被接口继承,并且一个接口可以继承多个接口。接口扩展了单根继承体系。
4:一个类可以实现多个接口。但是接口不能实现接口。
5:解决了继承耦合性高的问题,且可让实现类继承或实现其它类或接口
*/
修饰符 interface Iname{};
抽象类与接口的区别:
抽象类abstract | 接口interface |
---|---|
模板信息。子类都具备的基本特征,在抽象父类中定义抽象方法进行描述。比如男人,不管黄种人,黑种人,白种人,身体构造都是一样的。 | 特殊信息。子类不一定都具备的功能,只是在某些类中存在的功能。比如人类的接口,男人跟女人的区别。 |
单继承 子类要么全部实现,要么继续抽象。 | 子类可以多继承,扩展了单继承体系。 接口不能实现接口。 |
类中有抽象方法–一定是–>抽象类 类中无抽象类中–可能是–>抽象类 | 接口~=抽象类中的方法都是抽象方法。 |
Java8后,增加了default方法和static方法,这两种方法完全可以有方法体。 |
继承与实现的区别:
继承extends | 实现implements |
---|---|
子类继承父类,让子类与父类在本质上属于同一种事物。 | 类实现接口,只是让类拥有了接口的某种功能,但不是同一种事物。 |
一:Java单继承(借用内部类可以扩展成多继承) class 子类 extends 父类{} 二:接口多继承(扩展了单根继承体系) 接口 extends 接口1,接口2,…{} | 一:多实现接口 class 实现类 implements 接口1,接口2,…{} 二:接口不能实现接口 implements Iname1 implements Iname2 |
super与this
super | this | |
---|---|---|
方法 | super.方法 调用父类的方法。 | this.方法 访问本类的方法,如果没有则访问父类的方法。 |
属性 | super(属性) 调用父类的构造函数。 当父类有属性时,必须通过super(属性)声明,并放在子类的改造方法的首行。 | this.属性 访问本类的属性,如果没有则访问父类的属性。 |
当父类与子类存在同名方法或者属性时
final
局部->全局
修饰 | 变化 |
---|---|
变量 | 变量变为常量(只能初始化,不能修改)。方法中的形参只能读不能改。 |
方法 | 方法不能被重写 |
类 | 类无法被继承 |
多态
一个事物的多种形态(多态=继承+重写+向上/向下转型)。在运行时才知道引用的变量所指向的具体实现对象。
多态主要形式:
1:方法的重载与重写。
2:对象的多样性。包括向上转型,向下转型。
向上转型:子类对象->父类对象。使用子类的构造方法去创建父类的对象,例如 父类 父类对象=new 子类();
向下转型:父类对象->子类对象。将父类对象还原成子类对象,例如 (子类)父类对象;
父类 | 子类 | 向上转型产生的对象去调用方法 |
---|---|---|
存在方法原型 | 未重写 | 调用父类中的方法实现 |
存在方法原型 | 重写 | 调用子类中的方法实现 |
不存在方法原型 | 新增方法 | 调用不到子类方法,若需调用则使用向下转型 |
//判断a对象是否为A类型a instanceof A;
方法重载与重写
重载Override | 重写 | |
---|---|---|
实现 | 方法名相同,访问修饰符,返回类型与形参列表不同(常见的构造器重载)。 | 外壳不变,内核重写(形参列表不变,修改方法体中的代码)。 返回类型:父类返回值或父类返回值的派生类 访问修饰符:子类权限>=父类权限 |
区分 | 编写期间 | 运行期间 |
发生位置 | 同一个类中或者在子类中 | 继承类中。父类中存在方法原型,子类对父类方法进行覆盖。 |
throws异常 | 可以声明新的或更大级别的异常 | 子类级别>=父类级别 |
private方法能被重写吗
不能
final方法能被重写吗
不能
五大原则
SRP 单一职责原则
(Single Responsibility Principle)
类的功能要单一,不能包罗万象,跟杂货铺似的。
OCP 开放封闭原则
OCP(Open-Close Principle)
一个模块对于拓展是开放的,对于修改是封闭的,想要增加功能热烈欢迎,想要修改,哼,一万个不乐意。
LSP 里式替换原则
LSP(the Liskov Substitution Principle LSP)
子类可以替换父类出现在父类能够出现的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~
DIP 依赖倒置原则
DIP(the Dependency Inversion Principle DIP)
高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。就是你出国要说你是中国人,而不能说你是哪个村子的。比如说中国人是抽象的,下面有具体的xx省,xx市,xx县。你要依赖的是抽象的中国人,而不是你是xx村的。
ISP 接口分离原则
ISP (the Interface Segregation Principle ISP)
设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。就比如一个手机拥有打电话,看视频,玩游戏等功能,把这几个功能拆分成不同的接口,比在一个接口里要好的多。
常用类库
数据的处理
获取、传输、存储、分析、转换
序列化和反序列化
序列化是将对象的信息转换为可传输或可存储形式的过程。反序列化就是反过来让这些可传输的、可存储的信息变回对象。
传输的序列化除了安全性的考虑,因为涉及到和第三方通信,所以还有重要的一点是可读性和不变性。而存储的链路短,可控,所以更讲究效率。
传输最常用的序列化手段是JSON这样人眼可读的。而存储会使用protostuff这种将key值映射成编码来传输的。因为1,2,3比one、two、four更省空间更高效。但是传输中都用编码,解析时就很难判断它的意义。双方还要进行额外的约定。本来3代表four,中间加了一个three,3代表three的话,对方没有及时被通知,那么解析传输过来的消息就是错的。
反射
Java反射是在运行时,对于任何一个类,都可以知道这个类有哪些方法和属性。对于任何一个对象,都能对它的方法和属性进行调用。
常用数据转换工具,比如Spring的RequestParam、RequestBody、ResponseBody内部就用了反射机制。还有Jackson等工具类。甚至在业务代码中直接使用反射也是很常见的。比如设计一个AI助手问答机。想实现:
小A:我要搜索美女"冰冰"AI助手:OK,搜索"冰冰"小A:想知道她的"年龄"AI助手:21岁
上面这个JAVA实现是这样的:
Field field = 美女.class.getDeclaredField(年龄);field.setAccessible(true);return field.get(冰冰).toString();
动态代理
代理模式是为了提供增强的或不同的操作,而插入来替代实际对象的对象。这些操作涉及到与实际对象的通信,所以称为代理。
Spring主要的两大思想IoC和AOP。对于IoC,利用的是反射机制。而AOP使用了动态代理,当然底层也是反射。
JDK动态代理只能给有接口的类代理。本质是通过反射获取要执行的方法,并在执行前或者后加入一些代理处理操作。cglib本质上用继承的方法实现的,是通过动态生成一个子类去覆盖所要代理的类。用final修饰的不能被覆盖的就不代理了。spring动态代理是优先使用JDK动态代理,如果目标没有实现任何接口,则创建一个cglib代理。如果几个类实现了都实现了一个通用接口,比如Runnable,并且加了Component请spring来负责其生命周期。这时候会抛出一个Proxy代理异常。说期望加载一个Bean,实际上实现却不只一个。这时候可以在这个类上加下面标签强制使用cglib代理来解决。
@EnableAspectJAutoProxy(proxyTargetClass = true)