JAVA面向对象学习笔记(MLDN)
- 软件开发
- 2022-07-25
- 14热度
- 0评论
JAVA SE
数据类型和运算符
注释
- 单行注释
- 使用“//”开头,后面的单行内容均为注释
- 多行注释
- 以“/”开头,“/”结尾,之间的内容为注释
- 多行注释不能嵌套使用
- 文档注释
- 在eclipse中,输入“/**”+回车
- 帮助生成项目的API文档
标识符
- 定义
- 用来给变量、类、方法以及包命名
- 命名规则
- 1、必须以字母、下划线、美元符号$开头
- 2、其他部分可以是字母,下划线“_”,美元符,和数字的任意组合
- 3、大小写敏感,且长度无限制
- 4、不可以是JAVA的关键字
- 使用规范
- 1、给类起名时,每个单词的首字母大写
- 2、表示方法和变量的标识符:第一个单词小写,从第二个单词开始首字母大写,“驼峰原则”
JAVA中的关键字/保留字
变量
- 本质
- 一个“可操作的存储空间”,空间位置是确定的,但是里面放置什么值不确定。我们可以提哪个个变量名来访问“对应的存储空间”,从而操纵这个“存储空间”存储的值
- 声明变量格式
- type varName[=value][{,varName[=value]}]
- 如:int i=100;
- 注意
- 不建议一行声明多个变量
- 变量的类型
- 局部变量
- 定义
- 方法或语句块内部定义的变量。生命周期是从声明位置开始到方法或语句块执行完毕为止
- 定义
- 成员变量
- 定义
- 也叫实例变量,方法外部、类的内部定义的变量。从属于对象,生命周期伴随对象始终
- 成员变量会自行初始化
- int初始值 0
- double初始值 0.0
- char初始值 \u0000
- boolean初始值 false
- 定义
- 静态变量
- 定义
- 类变量,使用static定义。从属于类,生命周期伴随类始终,从类加载到卸载
- 定义
- 局部变量
常量
- 指固定的值,在java中主要利用关键字final 来定义一个常量,一旦初始化后不能再更改其值
- 声明格式
- final type
基本数据类型
- 数值型
- 整数类型
- byte
- 1字节=8位
- -2^7 ~ 2^7-1(-128~127)
- 1字节=8位
- short
- 2字节=16位
- -2^15 ~2^15-1(-32768~32767)
- 2字节=16位
- int
- 4字节=32位
- -2^31 ~2^31-1
- int a = 15;//整型常量默认是int类型
- int b = 015;//以0开头是八进制
- int c = 0x15;//以0x开头是十六进制
- int d = 0b1101;//以0b开头是二进制
- -2^31 ~2^31-1
- 4字节=32位
- long
- 8字节=64位
- -2^63 ~ 2^63-1
- long gp = 7400000000L;//后面加L指这是个long类型的常量
- -2^63 ~ 2^63-1
- 8字节=64位
- byte
- 浮点类型
- float
- 4字节
- -3.403E38 ~3.403E38
- float g = 3.14f;//3.14是double型,加f转为float常量
- -3.403E38 ~3.403E38
- 4字节
- double
- 8字节
- -1.798E308 ~1.798E308
- double h = 314e2;
double i = 31400;
System.out.println(hi);//这俩写法是相等的
- double h = 314e2;
- -1.798E308 ~1.798E308
- 8字节
- 浮点类型常量两种表示方式
- 十进制
- 3.14
- 314.0
- 0.314
- 科学计数法
- 314e2
- e2表示 10^2
- 314E2
- 314E-2
- 314e2
- 十进制
-
浮点数是不精确的,一定不能用于比较
- 例1
- float a1 = 0.1f;
double a2 = 1.0/10;
System.out.println(a1a2);//结果为false
- float a1 = 0.1f;
- 例2
- float d1 = 423432423f;
float d2 = d1 + 1;
if(d1d2){
System.out.println("d1d2");//输出结果为d1d2
}else{
System.out.println("d1!=d2");
}
- float d1 = 423432423f;
- 金融类的比较,java.math包下
- BigInteger
- 实现任意精度的整数运算
- BigDecimal
- 实现任意精度的浮点运算
- BigDecimal bd = BigDecimal.valueOf(1.0);
bd = bd.subtract(BigDecimal.valueOf(0.1));
bd = bd.subtract(BigDecimal.valueOf(0.1));
bd = bd.subtract(BigDecimal.valueOf(0.1));
bd = bd.subtract(BigDecimal.valueOf(0.1));
bd = bd.subtract(BigDecimal.valueOf(0.1));
System.out.println(bd);//0.5
System.out.println(1.0-0.1-0.1-0.1-0.1-0.1);//0.5000000000000001 - BigDecimal bd1 = BigDecimal.valueOf(0.1);
BigDecimal bd2 = BigDecimal.valueOf(1.0/10);
System.out.println(bd1.equals(bd2));//true
- BigDecimal bd = BigDecimal.valueOf(1.0);
- 实现任意精度的浮点运算
- BigInteger
- 例1
- float
- 整数类型
- 字符型
- char
- 字符型变量/常量
- 在java中用单引号来表示字符常量
- char q ='T';
char w = '朱';
char e ='\u0061';//a
- char q ='T';
- char类型用来表示在Unicide编码表中的字符
-
String类,其实是字符序列(char sequence)
- String st = "abc;
- 在java中用单引号来表示字符常量
- 转义字符
- \n
- 换行符
- \t
- 制表符
- \r
- 回车
- \b
- 退格
- \n
- 字符型变量/常量
- char
- 布尔型
- boolean
- 1位,不是1字节
- true
- boolean b = true;
- false
- boolean b = false;
- true
- boolean man = true;
if (man){ //极端不推荐使用 man true
System.out.println("男性");
}
- 1位,不是1字节
- boolean
引用数据类型 4字节
- 类 class
- 接口 interface
- 数组
运算符
-
算数运算符
- 二元运算符,需要两个操作数
- +、-、*、/、%
- 整数运算
- 两个操作数,有一个long,则结果也为long
- 没有long时,结果为int,即使操作数全为short、byte,结果也为int
- 浮点运算
- 如果两个操作数有一个为double,则结果为double
- 只有两个操作数都是float,则结果采薇float
- 取模运算
- 其操作数可以为浮点数,一般使用整数,结果是“余数”,余数符号和左边操作数相同,如:7%3=1,-7%3=-1,7%-3=1
- 算数运算符中,++,--,属于一元运算符,只需要一个操作数
- 整数运算
- +、-、*、/、%
- 一元运算符
- int me = 3;
int newme =me++;// me赋值给newme后,再自增赋值给me
System.out.println("me="+me+"\nnewme="+newme); - int me1 = 3;
int newme1 = ++me;//me1自增后赋值给newme1,me1自身没变
System.out.println("me1="+me1+"\nnewme1="+newme1);
- int me = 3;
- 二元运算符,需要两个操作数
- 赋值运算符与扩展运算符
- +=
- a+=b 等价于 a=a+b
- -=
- a-=b 等价于 a=a-b
- *=
- a=b 等价于 a=ab
- a=b+3 等价于 a=a(b+3)
- /=
- a/=b 等价于 a=a/b
- %=
- a%=b 等价于a=a%b
- +=
- 关系运算符
- 关系运算符结果为布尔值 true/false
-
- 等于
- !=
- 不等于
- >
- 大于
- <
- 小于
-
=
- 大于等于
- <=
- 小于等于
- 逻辑运算符
- 操作数和运算结果都是布尔值
- 逻辑与
- &(与)
- 两个操作数为true,结果才是true,否则是false
- &(与)
- 逻辑或
- |(或)
- 两个操作数只要有一个是true,则结果为true
- |(或)
- 短路与
- &&(与)
- 只要有一个为false,则直接返回false
- &&(与)
- 短路或
- || (或)
- 只要有一个为true,则直接返回true
- || (或)
- 逻辑非
- !(非)
- 取反,!false则为true,!true则为false
- !(非)
- 逻辑异或
- ^(异或)
- 相同为false,不同为true
- ^(异或)
- 位运算符
- 取反
- ~
- 按位与
- &
- 按位异或
- |
- 左移运算符,左移一位相当于乘2
- <<
- 右移运算符,右移一位相当于除2
- >>
- 取反
- 条件运算符
- 三目条件运算符,语法格式:x ? y :z
- 如果x是true,则整个表达式返回y;如果x是false,则整个表达式返回z
- //测试三目(三元)运算符
int score = 80 ;
String type = score < 60 ? "不及格":"及格";
System.out.println(type); - int x = -100;
System.out.println(x > 0 ?1:(x 0 ? 0:-1));
- 字符串连接符
- 字符串不是基本数据类型,是对象
- +
- 加号左右两边,只要有一个为字符串,则变为字符串连接符
- 运算符优先级
- 不需要刻意去记,通过小括号去定义运算优先级
- 算术运算符 >> 关系运算符 >> 逻辑运算符 >> 赋值运算符
- 逻辑非 > 逻辑与 > 逻辑或
自动类型转换
- 自动转换
- 容量小的(范围)自动转换为容量大的
- int和long 转化为 float 和double 时会有精度损失
- 可以直接将整型常量赋值给byte、short、char等类型变量,不需进行强制类型转换,只要不超出其表述范围
- 容量小的(范围)自动转换为容量大的
- 强制转换
- 语法格式: (type)var ;//type为想要转换成的目标数据类型
- 转换时注意精度损失
- 基本类型转换常见问题
- 操作比较大数时,留意是否溢出
- int money = 1000000000; //10亿
int years = 20;
//返回的total是负数,超过了int的范围
int total = moneyyears;
System.out.println("total="+total);
//返回的total仍然是负数。默认是int,因此结果会转成int值,再转成long。但是已经发生//了数据丢失
long total1 = moneyyears;
System.out.println("total1="+total1);
//返回的total2正确:先将一个因子变成long,整个表达式发生提升。全部用long来计算。
long total2 = money*((long)years);
System.out.println("total2="+total2);
- int money = 1000000000; //10亿
- L和l问题
- int l = 2; //分不清是L还是1,
long a = 23451l;//建议使用大写L
System.out.println(l+1);
- int l = 2; //分不清是L还是1,
- 操作比较大数时,留意是否溢出
控制语句
顺序结构
选择结构
- 如果... 则...
- 布尔表达式表示区间的情况,只能用ifesle
- 表示多值判断的情况,可以用ifelse,或者switch
- if单选择结构
- if(布尔表达式){
语句块;
} - int i = (int)(6*Math.random()+1);//[1,6)
if(i<=3){
System.out.println("小");
}
- if(布尔表达式){
- if-else双选择结构
- if(布尔表达式){
语句块;
}else{
语句块;
}
- if(布尔表达式){
- if-else if -else 多选择结构
-
switch
- /**
- switch(表达式){
- case 值1:
- 语句序列1;
- [break];
- case 值2:
- 语句序列2;
- [break];
- ----------
- [default]:
- 默认语句;
- }
- int month = (int)(1 + 12 * Math.random());
System.out.println("月份"+month);
- int month = (int)(1 + 12 * Math.random());
switch(month){
case 1:
System.out.println("一月份,过新年!");
break;
case 2:
System.out.println("二月份,开春了!");
break;
default:
System.out.println("其他月份!");
}
循环结构
- 分类
- 当型,使用较多
- 直到型,用的比较少
- while循环结构,先判断后执行
- //测试while循环
//计算1-100的和5050
int k = 1;
int sum = 0;
- //测试while循环
while(k<=100){
sum = sum + k;
k++;
System.out.println("循环中的sum:"+sum);
}
System.out.println(sum);
- do while先执行后判断,用少,可用while取代
- for循环,最常用
-
- 1、执行初始化语句: i=1;
-
- 2、判断i<=100;
- 3、执行循环体;
- 4、步进迭代;
- 5、回到第二步继续判断;
- int sum = 0;
for(i=1;i<=100;i++){
sum = sum + i;
System.out.println("循环中的sum:"+sum);
}
System.out.println(sum);
- 嵌套循环
- 在一个循环语句内部再嵌套一个或多个循环
- for(int n=1;n<=5;n++){
for(int j=1;j<=5;j++){
System.out.print(n+"\t");
}
System.out.println();
} - //打印99乘法表
for (int m=1;m<=9;m++){
for(int c=1;c<=m;c++){
System.out.print(c+""+m+"="+(cm)+"\t");
}
System.out.println();
}
- break和continue
- break用来结束全部循环
- continue用来终止某次循环过程,跳到下次循环
方法的定义及调用
面向对象
类与对象
- 面向过程
- 面对于一个问题的解决方案,更多情况下是不会做出重用的设计思考的
- 面向对象
- 主要的设计形式为模块化设计,并且可以进行重用配置。更多情况下考虑的是标准,在使用的时候根据标准进行拼装
- 三大特性
- 封装
- 内部操作对外不可见,当内部操作不可直接使用的时候才是安全的
- 继承
- 在已有结构基础上,继续进行功能扩充
- 多态
- 是在继承性的基础上扩充而来的概念,指的是类型的转换处理
- 封装
- 开发的三个步骤
- OOA
- 面向对象分析
- OOD
- 面向对象设计
- OOP
- 面向对象编程
- OOA
- 类
- 对某一类事物的共性抽象概念,而对象描述的是一个具体的产物
- 两个组成
- 成员属性(field)
- 有些时候为了简化,称其为属性
- 操作方法(method)
- 定义对象具有的处理行为
- 成员属性(field)
- 定义
- class Person { //定义一个类
String name ; //人员姓名
int age; //人的年龄
public void tell() { //定义一个方法
System.out.println("姓名:"+name+"、年龄:"+age);
}
} - 这个类中有两个属性,一个方法
- class Person { //定义一个类
- 对象
- 对象描述的是一个具体的产物
- 声明并实例化对象
- 方法一:类名称 对象名称=new 类名称()
- 方法二:
声明对象:类名称 对象名称=null
实例化对象:对象名称=new 类名称()
- 对类中的操作调用
- 实例化对象.属性
- 实例化对象.方法()
- 对象内存分析
- 堆内存:保存的是对象的具体信息,堆内存的开辟是通过关键字new进行的
- 栈内存:存的是对象在堆内存中的地址信息
- 对象必须实例化之后才能使用,否则无法使用
- 引用传递与垃圾产生分析
- 所谓的垃圾空间就是没有任何栈内存所指向的堆内存空间,所有垃圾将被GC(Garbage Collector/垃圾收集器)不定期就行回收并且释放无用内存空间,但如果垃圾过多,一定影响到GC的处理性能,从而降低整体的程序性能,在实际开发中对于垃圾产生应该越少越好
- 一个栈内存只能有一个堆内存的地址数据,如果发生更改,则之前的地址数据将从此栈内存中彻底消失
深入分析类与对象
- 成员属性封装
- 可通过private关键字修饰变量,对外部不可见,但是对内部可见的,防止外部程序随意修改
- 【setter、getter】设置或取得属性可以使用setXxx()/getXxx()方法
- 类的所有属性必须要用private进行封装(98%的情况),要提供get、set方法
- 构造方法与匿名对象
- 构造方法
- 类中属性如有很多个,需要写很多个set方法,很麻烦,可以通过构造方法实现实例化对象中的属性初始化处理
- 只有在关键字new的时候使用构造方法
- 构造方法名称必须与类名称保持一致
- 构造方法不允许设置任何的返回值类型,即没有返回值定义
- 构造方法是在使用关键字new实例化对象时自动调用的
- 对象实例化格式
- Person per=new Person()
- Person 定义对象所属类型
- per实例化对象名称
- new开辟一块新堆内存空间
- Person()调用无参构造
- Person per=new Person("张三",18)
- Person 定义对象所属类型
- per实例化对象名称
- new开辟一块新堆内存空间
- Person("张三",18)调用有参构造
- 所有的类都会提供有无参构造方法,在程序编译时自动创建的;如果重新定义构造方法的话,无参构造方法则不会被创建
- 多个构造方法定义时,可以有顺序,按照参数个数排序定义
- Person per=new Person()
-
结论:一个类中至少存在一个构造方法,永恒存在
-
疑问
- 构造方法为什么不用void定义
- 程序编译器及执行都是根据代码结构进行处理,如果使用void,则结构与普通方法相同,则会被认为是普通方法;构造方法是类对象实例化时使用的,普通方法要在实例化之后才能使用
- setter和构造方法区别
- 构造方法设置数据,只能初始化数据,无法修改,setter方法除了设置数据,还可以修改数据
- 构造方法为什么不用void定义
- 匿名对象
- 此对象没有被引用,调用完tell方法后,将成为垃圾,被GC进行回收与释放
- 只要是方法可以传递任意数据类型(包括基本数据类型、引用数据类型)
- 构造方法
this关键字
- this调用本类属性
- 三类结构的描述
- 当前类中的属性:this.属性
- 当前类中的方法(普通方法、构造方法):this()、this.方法名称()
- 描述当前对象
- 使用this调用当前类中属性
- 按照就近取用原则,name=name,还是取的构造方法中的name,需要加上this,表示取的是类中的name,即本类属性
- 在以后的程序代码中,只要访问本类属性,加上this进行访问,养成习惯
- 三类结构的描述
- this调用本类方法
- 构造方法调用:this()
- 给一个类所有的构造方法都要打印一句话,传统方法是每个方法都加上输出语句,会导致代码重复,优化后方法是,在有参构造去调用无参构造的方法
- 构造方法必须在实例化新对象的时候调用,所以this()的语句只允许放在构造方法的首行
- 构造方法互相调用,会大大减少代码的重复度
- 普通方法调用:this.方法名称()
- 构造方法调用:this()
-
简单JAVA类
- 可以描述某一类信息的程序类,在这个类中没有特别复杂的逻辑操作,只作为信息存储的媒介存在
- 核心结构
- 类名称一定要有意义,可以明确描述某一类事物
- 类之中的所有属性都小private方法进行封装,同时封装后的属性提供setter、getter方法
- 类之中可以提供无数多个构造方法,但必须保留无参构造方法
- 类之中不允许出现任何输出语句,所有内容获取必须返回
- 【非必须】可以提供一个获取对象详细信息的方法,getinfo()
- 简单java类很重要,必须熟练编写
static关键字
-
使用static定义属性
- 在一个类中,所有属性一旦定义实际上内容都交由各自的堆内存空间所保存
- static修饰的属性,为公共属性,存在全局数据区
- 对static属性访问需要注意:由于其本身是公共属性,虽然可已通过对象进行访问,但是最好的做好是通过所有对象的最高代表(类)进行访问
- static在类中,不受类实例化对象的控制,即类没有实例化时,static修饰的属性可以使用
- 在进行类设计的时候,首选非static属性(95%),而考虑公共信息存储时使用static属性,非static属性必须要实例化对象产生之后使用,static属性可以在对象没有实例化时进行使用
- 使用static定义方法
- static方法只允许调用static属性和static方法
- 非static方法允许调用static属性和static方法
代码块
- 在程序中使用{}定义的结构成为代码块
- 类型
- 普通代码块
- 定义在一个方法中的代码块
- 可以在一个方法之中进行一些结构的拆分,以防止相同变量的名称所带来的相互影响
- 构造块
- 定义在一个类之中的
- 构造块会先于构造方法执行
- 每次实例化对象都会调用构造块中的语句
- 定义在一个类之中的
- 静态块
- 使用static关键字定义的代码块
- 主类中定义静态块
- 非主类中定义静态块
- 静态代码块会优先于构造块执行,并且不管有多少个实例化对象出现,静态代码块只执行一次,主要目的是为了类中的静态属性的初始化
- 静态代码块优先于主方法先执行
- 使用static关键字定义的代码块
- 同步代码块
- 多线程时使用
- 普通代码块
面向对象案例
数组
- 数组的基本定义
- 一组相关变量的集合
- 定义格式
- 动态初始化
- 数据类型 数组名称 = new 数据类型[长度]
- int data[] = new[3]
- 数据类型[] 数组名称 = new 数据类型[长度]
- 数据类型 数组名称 = new 数据类型[长度]
-
静态初始化
- 简化格式:数据类型 数组名称[] {数据1,数据2,数据3,...}
- 完整格式:数据类型 数组名称[] = new 数据类型[]{数据1,数据2,数据3,...}
- 动态初始化
- 数组中通过脚标进行每个元素的访问,脚标从0开始,可以访问范围 0 ~ 数组长度-1
-
数组内存分析
-
foreach迭代输出
- 传统方法通过for循环数组中的元素,实现迭代输出,处理不好会出现数组下标越界的异常
- jdk1.5之后,通过foreach(增强型的for循环)减少数组下标的影响
- 语法形式
- for (数据类型 变量:数组 | 集合) {}
- 一维数组
- int data[] = new int[]{1,2,3,4,5}
for (int tmp : data){
system.out.println(tmp)
}
- int data[] = new int[]{1,2,3,4,5}
- 二维数组
- int data[][]=new int[][]{{1,2,3,4,5},{1,2,3},{5,6,7,8}};
for(int temp[] : data){
for(int x : temp){
system.out.println(x+"、");
}
system.out.println();
}
- int data[][]=new int[][]{{1,2,3,4,5},{1,2,3},{5,6,7,8}};
- 二维数组
- 数组的动态初始化
- 数据类型 数组名称[][]=new 数据类型[行个数][列个数]
- 数组的静态初始化
- 数据类型 数组名称[][]=new 数据类型[][]{{数据,数据,...},{数据,数据,...},...}
- 数组的动态初始化
- 数组与方法
- 数组的引用传递
- 通过方法可以接收或者返回数组
- 数组的引用传递
- 数组排序
- 数据依次排序过程
- 代码实现过程
class ArrayUtil{ public static sort(int data[]){ //进行数组排序处理 for (int x=0; x<data.length; x++){ for (int y=0; y<data.length-x-1; y++){ if (data[y] > data[y+1]){ //交换数据 int temp = data[y]; data[y] = data[y+1]; data[y+1] = temp; } } } } public static void printArray(int temp[]){ //打印数组 for (int x=0;x<temp.length;x++){ System.out.print(temp[x]+"、"); } System.out.println(); } } public class ArrayDemo { public static void main (String args[]){ int data[] = new int[]{8,9,0,2,3,5,10,7,6,1}; ArrayUtil.sort(data[]); } ArrayUtil.printArray(data); } }
- 如果发现类中没有属性存在的意义,那么定义的方法就没有必要使用普通方法,因为普通方法需要在实例化对象产生情况下才能使用
- 数据依次排序过程
- 数组反转
- 进行前后转置处理,即首尾交换
- 处理方式一:
public class ArrayReverse2 { public static void main(String[] args) { int data[] = new int[]{1,2,3,4,5,6,7,8,9}; int temp[] = new int[data.length]; int foo = temp.length - 1; for (int x=0; x< data.length; x++){ temp[foo --] = data[x]; } data = temp; printArray(data); } public static void printArray(int temp[]){ for (int x=0;x<temp.length;x++){ System.out.print(temp[x]+"、"); } System.out.println(); } }
内存分析如下,temp的内容指向data时,原来的data成为垃圾
- 处理方式二:在一个数组上进行转置
public class ArryaRevers { public static void main(String[] args) { int data[] = new int[]{1,2,3,4,5,6,7,8,9}; int len = data.length; for (int y=0;y<=len/2;y++){ int temp= data[y]; data[y]=data[len-y-1]; data[len-y-1]=temp; } printArray(data); } public static void printArray(int temp[]){ for (int x=0;x<temp.length;x++){ System.out.print(temp[x]+"、"); } System.out.println(); }
- 数组相关类库
- 数组排序
- java.util.Arrays.sort(数组名称)
- 数组拷贝
- System.arraycopy(源数组,源数组开始点,目标数组,目标数组开始点,拷贝长度)
- 自己写方法实现:
public class ArraySort { public static void main(String[] args) { int[] a = new int[]{1,2,3,4,5,6}; int[] b = new int[]{11,22,33,44,55,66}; ArrayCopy(a,2,b,2,3); printArray(b); } public static void ArrayCopy(int[] src,int sindex,int[] dst, int dindex,int len){ for (int x=0;x<len; x++){ dst[sindex ++] = src[dindex ++]; } } public static void printArray(int temp[]){ for (int x=0;x<temp.length;x++){ System.out.print(temp[x]+"、"); } System.out.println(); } }
- 数组排序
- 方法可变参数
- 可变参数最大作用在于,在以后进行一些程序类设计或者开发者调用的时候,利用此种形式可以避免数组的传递操作,可变参数的本质:依然是数组,但是比传统的多了灵活性。
public static int sum(int ... data){ //变种数组 int sum =0; for (int temp : data){ sum += temp; } return sum; }
- 对象数组
- 对象数组定义格式:
- 动态初始化:类 对象数组名称[] = new 类[长度];
- 静态初始化:类 对象数组名称[] = new 类[]{实例化对象1,实例化对象2,...};
- 动态初始化:类 对象数组名称[] = new 类[长度];
- 所有开发都不可能离开对象数组
- 缺陷:长度固定
- 优点:线性保存,根据索引访问,速度较快(时间复杂度为“1”)
- 对象数组定义格式:
引用传递
- 类关联结构
- 人和车的关系:可以独立存在,但是没有相互依赖关系
- 自身关联
- 一个人可以有多个孩子,多个孩子也可以有车的关系
- 合成设计模式
- 任何人类设计的产品都是可以拆分的,而后进行重新组合,这样的设计在JAVA之中被称为合成设计模式。
数据表与简单JAVA类映射转换
- 简单java类是现在面向对象设计的主要分析基础,简单java类是根据数据表的结构来实现。
- 数据表与简单java类映射关系如下
- 数据实体表设计 = 类的定义
- 表中的字段 = 类的成员属性
- 表的外键关联 = 引用关联
- 表的一行记录 = 类的一个实例化对象
- 表的多行记录 = 对象数组
- 对于数据表与简单java类之间映射的最好的解决步骤:
- 先抛开所有的关联字段不看,写出类的基本组成
- 再通过引用配置关联字段的关系
- 对应关系
- 一对多映射
- 多对多映射
- 复杂多对多映射
- (需要练习此实例代码)
String类
- String类简介
- 字符串严格意义不是基本数据类型,java为了方便开发者编写,利用JVM制造了一种可以简单实用的String类,并且可以向基本数据类型一样赋值处理
- String类对象实例化
String str = "这是个字符串"
//直接定义String str = new String("这是个字符串")
//利用构造方法定义
- String类里之所以可以保存字符串主要是其中定义了一个数组,在String字符串中的每个字符数据是保存在数组之中。
- JDK1.9及之后针对字符串定义形式增多了(通过查看JDK源代码),String类中的数组类型采用的 byte 类型;1.8以前String保存的是 char 数组;
- 字符串比较
- 字符串比较,使用String类提供的 equals()方法;
strA.equals(strB);
- ""与"equals()"的区别:
- 用于数值的比较,用于对象比较的话是比较内存地址的数值;
- equals()
- 字符串比较,使用String类提供的 equals()方法;
- 字符串常量
- 任何使用双引号定义的字符串常量,实际上描述的都是一个String类的匿名对象
- 匿名对象调用equals(),可能会引起空指针异常
- 字符串常量调用equals(),可以避免空指针异常
- String 类对象两种实例化方式比较
String str = "这是个字符串"
将一个字符串直接赋值给String类的对象 ,就可以实例化处理,只开辟一块堆内存和一块栈内存空间
String strA = "aaa"; String StrB = "aaa"; System.out.println(strA == strB); //返回true
java底层在堆内存开辟一块空间提供字符串池 `strA` 赋值时,会在字符串池生成一个 "aaa"的字符串, `strB`赋值时,会先去查找字符串池, 如果有"aaa"就进行复用节省内存空间提升性能, 所以`strA`和`strB`会指向同一块内存空间。
String str = new String("aaa")
构造方法实例化String类对象- 会开辟两块内存空间,并且匿名对象开辟的空间将成为垃圾,直接赋值会更加节约空间
- 构造方法实例化的对象实际是属于自己专用的内存空间,但是在String类中也提供有帮助开发手工入池的情况,方法:public String intern();
String strB = new String("aaa").intern();
//指向池中,但是这种做法太啰嗦
- String对象(常量)池
-对象池的目的是实现数据共享,以String对象为例,里面内容主要为了重用,属于共享设计。- 对象池又分为两种
- 静态常量池
String strA = "www.baidu.com"; String strB = "www."+"baidu"+".com"; System.out.println(strA == strB); //返回true
- 运行时常量池
String info = "baidu" strA = "www.baidu.com"; strB = "www."+info+".com"; System.out.println(strA == strB); //返回false
- 静态常量池
- 对象池又分为两种
- 字符串修改
- 字符串内容不可改变
public class StringDemo{ public static void main(String args[]){ String str = "www."; str += "baidu"; str = str + ".com"; System.out.println(str); } }
以上代码内存分析图如下:
通过以上可以发现,整个处理过程中,字符串常量内容并未发生改变,改变的是String类对象的引用,这种改变会产生大量的垃圾空间。
开发过程中,String类不要进行内容的频繁修改。 -
JAVA中的主方法
public static void main(String args[])
- public:主方法是一切的开始点,开始点一定是公共的;
- static:程序的执行是通过类名称完成,此方法由类直接调用;
- void:主方法是一切的起点,一旦开始就没有返回的可能
- mian:系统定义好的方法名称
- String args[]:字符串数组,可以实现程序启动参数的接收;
String类常用方法
- JavaDoc 文档
- JavaDoc即API文档
- 类的完整定义
- 类的相关说明
- 成员属性摘要
- 构造方法摘要
- 方法摘要
- 在JDk1.9之前,所有Java常用类库会在JVM启动时进行全部加载,性能会有所下降;在1.9开始提供有模块化设计,将一些程序类放在不同模块中。
- 在模块中有大量程序开发包,String类在 java.lang 包
- JavaDoc即API文档
- 字符串与字符数组
方法名 | 类型 | 描述 |
---|---|---|
public String(cahr[] value) | 构造 | 将传入的全部字符数组变成字符串 |
public String (char[] value,int offset,int count) | 构造 | 将部分字符数组变成字符串 |
public char charAt(int index) | 普通方法 | 获取指定索引位置的字符 |
public char[] toCharArray() | 普通方法 | 将字符串中的数据以字符数组方式返回 |
//获取指定索引位置的字符
public class StringDemo{
public static void main(String args[]){
String str = "www.baidu.com";
char c = str.charAt(5);
System.out.println(c); //输出“a”
}
}
// 字符串与字符数组的转换
public class StringDemo{
public static void main(String args[]){
String str = "helloworld";
char[] c = str.toCharArray(); //将字符串变为字符数组
for (int x=0 ;x < c.lengtg; x++){
c[x] -= 32 ; //编码减少32
}
//将处理后的字符数组交给String变为字符串
String newc = new String(c);
System.out.println(newc); //输出大写的“HEllOWORLD”
System.out.println(new String(newc,0,5)); //输出“HELLO”
}
}
//判断某个字符串中的数据,是否由数字组成
- 先将字符串变为字符数组
- 判断每一个字符是否在数字范围,即"0"~"9"
- 如果有一位不是数字,则表示验证失败
public class StringDemo{
public static void main(String args[]){
String str = "helloworld";
System.out.println(isNumber(str) ? "是由数字组成":"不是由数字组成");
System.out.println("123" ? "是由数字组成":"不是由数字组成");
}
public static boolean isNumber(String str){
char c = str.toCahrArray();
for (int x = 0 ;x < c.length ;x ++){
if (c[x] < "0" || c[x] > "9"){
return false; //后面不再判断
}
}
return true;
}
}
- 字符串与字节数组
字符串与字节数组也可以实现转换,当进行字符串与字节转换时,其主要目的是为了进行二进制数据传输,或者进行编码转换。
方法名 | 类型 | 描述 |
---|---|---|
public String(byte[] bytes) | 构造 | 将全部的字节数组变为字符串 |
public String(byte[] bytes, int offset, int lengtg) | 构造 | 将部分字节数组变为字符串 |
public byte[] getBytes[] | 普通 | 将字符串转为字节数组 |
public byte[] getBytes(String charsetName) throws UnsupportedEncodingException | 普通 | 编码转换 |
public class StringDemo{
public static void main(String args[]){
String str = "helloworld";
byte data[] = str.getBytes(); //将字符串变为字节数组
for (int x = 0 ;x < data.length ; x++){
data[x] -= 32 ;
}
System.out.println(data); //输出大写的“HEllOWORLD”
System.out.println(new String(data,0,5)); //输出“HELLO”
}
}
//字节是有长度限制的,-128 ~ 127 之间
- 字符串比较
最为常用的方法 equals(),但是进行大小写时是区分的,除了qquals()外,还有其他比较方法:
方法名 | 类型 | 描述 |
---|---|---|
public boolean equals(String anObject) | 普通 | 区分大小写的相等判断 |
public boolean equalsIgnoreCase(String anObject) | 普通 | 不区分大小写的相等判断 |
public int compareTo(String anotherString) | 普通 | 进行字符串大小比较,该方法返回int类型 |
public int compareToIgnoreCase(String anotherString) | 普通 | 不区分大小写进行字符串大小比较 |
//观察大小写的比较
public class StringDemo{
public static void main(String args[]){
String strA = "helloworld";
String strB = "HELLOWORLD";
System.out.println(strA.equals(strB)); //输出false
}
}
//
public class StringDemo{
public static void main(String args[]){
String strA = "helloworld";
String strB = "helloworlD";
System.out.println(strA.compareTo(strB)); //返回 d - D 的差值
System.out.println(strB.compareTo(strA)); //返回 D - d 的差值
}
}
public class StringDemo{
public static void main(String args[]){
String strA = "helloworld";
String strB = "helloworlD";
System.out.println(strA.compareToIgnoreCase(strB)); //返回 0
}
}
- 字符串查找
方法名 | 类型 | 描述 |
---|---|---|
public boolean contains(String s) | 普通 | 判断此字符串是否存在 |
public int indexOf(String str) | 普通 | 从头查找指定字符串位置,找不到返回 -1 |
public int indexOf(String str, int fromIndex) | 普通 | 从指定位置查找指定字符串位置,找不到返回 -1 |
public int lastIndexOf(String str) | 普通 | 由后向前查找指定字符串位置,找不到返回 -1 |
public int lastIndexOf(String str, int fromIndex) | 普通 | 从指定位置由后向前查找指定字符串位置,找不到返回 -1 |
public boolean startsWith(String prefix) | 普通 | 判断是否以指定的字符串开头 |
public boolean startsWith(String prefix, int toffSet) | 普通 | 由指定位置判断是否以指定的字符串开头 |
public boolean endsWith(String suffix) | 普通 | 判断是否以指定字符串结尾 |
//判断子字符串是否存在
public class StringDemo{
public static void main(String args[]){
String str = "www.baidu.com";
System.out.println(str.contains("baidu")); //返回true
System.out.println(str.contains("hello")); //返回false
}
}
//此方法,在jdk1.5 之后存在
//在jdk1.5 之前,需要通过 indexOf() 方法判断子字符串是否存在,是为了查询子字符串的位置,用来确定索引的位置,indexOf()是由前向后查找的
public class StringDemo{
public static void main(String args[]){
String str = "www.baidu.com";
System.out.println(str.indexOf("baidu")); //返回4,子字符串出现的位置
System.out.println(str.indexOf("hello")); //返回-1 ,表示不存在
}
}
- 字符串替换
方法名 | 类型 | 描述 |
---|---|---|
public String replaceAll(String regex, String replacement) | 普通 | 全部替换 |
public String replaceFirst(String regex, String replacement) | 普通 | 替换首个 |
public class StringDemo{
public static void main(String args[]){
String str = "www.baidu.com";
System.out.println(str.replaceAll(".","_"); //输出“www_baidu_com”
System.out.println(str.replaceFirst(".","_"); //输出“www_baidu.com”
}
}
- 字符串拆分
方法名 | 类型 | 描述 |
---|---|---|
public String[] split(String regex) | 普通 | 按照指定的字符串全部拆分 |
public String[] split(String regex, int limit) | 普通 | 按照指定的字符串拆分为指定个数 |
public class StringDemo{
public static void main(String args[]){
String str = "hello world hello baidu";
String results[] = str.split(" "); //按照空格拆分
String results2[] = str.split(" ",2); //按照空格拆分成两个
for (int x = 0 ;x < results.lengtg; x++){
System.out.println(results[x]);
}
}
}
有时候也会有拆不开的情况,可能是正则表达式的原因,拆分的依据需要使用双斜线进行转义,如按照“.”进行拆分的话,str.split("\\.")
;
- 字符串截取
方法名 | 类型 | 描述 |
---|---|---|
public String substring(int beginIndex) | 普通 | 从指定索引截取到结束 |
public String substring(int beginIndex, int endIndex) | 普通 | 截取指定索引范围中的子字符串 |
public class StringDemo{
public static void main(String args[]){
String str = "hello world hello baidu";
System.out.println(str.substring(4));
System.out.println(str.substring(4,8));
}
}
//实际开发中,字符串的索引都是通过IndexOf()计算出来的
public class StringDemo{
public static void main(String args[]){
//字符串结构:“用户id-photo-姓名.后缀”,要求截取姓名
String str = "admin-photo-张三.jpg";
int beginIndex = str.indexOf("-",str.indexOf("photo"));
int endIndex = str.indexOf(".");
System.out.println(str.substring(beginIndex + 1,endIndex));
}
}
- 字符串格式化
从jdk1.5开始,java提供格式化数据处理操作,类似于C语言中的格式化输出语句,可以利用占位符实现数据输出,对于占位符而言,常用的:字符串(%s)、字符(%c)、整数(%d)、小数(%f) 等来描述
方法名 | 类型 | 描述 |
---|---|---|
public static String format(String format, 各种类型 ... args) | 普通 | 根据指定结构进行文本格式化处理 |
public class StringDemo{
public static void main(String args[]){
String name = "张三";
int age = 18;
double score = 98.7654321;
String str = String.format("姓名:%s、年龄:%d、成绩:%5.2f。",name,age,score);
System.out.println(str);
}
}
- 字符串其他操作方法
| 方法名 | 类型 | 描述 |
|:-|:-|:-|
|public String concat(String str)|普通|描述的是字符串的连接|
|public String intern()|普通|字符串入池|
|public boolean isEmpty()|普通|判断字符串内容是否为空(非null)|
|public int length()|普通|字符串长度|
|public String trim()|普通|去除左右的空格信息|
|public String toUpperCase()|普通|转化为大写|
|public String toLowerCase|普通|转换为小写|
虽然Java中String类提供了大量的方法了,但是缺少一个首字母大写的方法,利用方法的组合即可
//自定义实现首字母大写的方法
class Stringutil{
public static String initCap(String str){
if (str == null || "".equals(str){
return str; //原样返回
}
if (str.length == 1){
return str.toUpperCase();
}
return str.substring(0,1).toUpperCase+str.substring(1);
}
}
继承的定义和使用
- 什么是继承
- 面向对象的第二特性
- 特点:可以扩充已有类的功能
- 为什么会有继承
- 良好的代码:结构合理,适于维护,可复用性高;
- 目前阶段,不可避免会面对代码重复的问题
- 继承的实现
- 需要依靠extends 关键字来实现
class 子类 extends 父类 {}
- 很多情况下会把子类成为派生类,父类成为超类SuperClass
- 继承实现的主要目的:子类可以重用父类的结构,并可实现功能的扩充,子类可以定义更多的内容,并且描述范围更小
- 需要依靠extends 关键字来实现
- 子类对象实例化流程
- 先实例化父类对象,才实例化子类对象
- 在子类构造方法第一句为:super()
- 该语句只允许放在子类构造方法第一句
- 该语句写与不写是一样的,都是只调用父类的无参构造方法
- 如父类无无参构造,则子类必须用super()明确的调用有参构造
- 目的是所有的属性可以进行空间的分配
- 继承的相关限制
1.java中不允许多重继承,只允许多层继承,但是多层继承需要有个度,理论上层次不应该超过三层。
class A{}
class B{}
class C extends A,B{} //多重继承,错误的写法
class A{}
class B extends A{}
class C extends B{} //多层继承
2.在进行继承关系定义的时候,子类可以继承父类中的所有操作结构。但对于私有操作属于隐式继承,所有的非私有操作属于显示继承
方法覆写
- 方法覆写
- 子类一旦继承父类,就继承了父类的全部定义,如发现父类设计不足并要保留父类中的方法或属性名称的情况下,就会发生覆写
- 当子类定义了与父类方法名称相同,参数类型及个数完全相同(跟父类方法一模一样)的时候,就称为方法的覆写
- 覆写的意义:在于优化子类的功能
- 如果要在子类中调用父类的方法,则必须使用super关键字
- 方法覆写的限制
- 被覆写的方法不能够拥有比父类方法更为严格的访问控制权限
- 目前三种访问权限:public > default > private,private权限最小;
- 如果父类方法用default定义,那子类方法只能使用public或default定义
- 如果父类用public定义,那子类方法只能用public定义
- private除了可以定义在属性,也可以定义在方法;private修饰的父类方法,在子类中重新定义时,不涉及覆写
- 在以后开发中,95%的情况下定义的方法使用public,覆写时也用public
- 请解释Override和Overloading的区别
- 1、中文含义
- Overloading叫重载
- 方法名称相同,参数类型及个数不同
- 没有权限限制
- 发生在一个类中
- Override叫覆写
- 方法名称、参数类型及个数、返回值,相同
- 被覆写方法不能拥有更严格的控制权限
- 发生在继承关系类中
- Overloading叫重载
- 2、在方法重载时,并未对返回类型做限制,但是好的习惯应该保持返回类型一致
- 1、中文含义
- 属性覆盖
- 当子类定义了与父类相同名称的成员时,称为属性覆盖
- 如果父类按照标准开发,对属性进行了封装,在子类中就不能通过super关键字来调用父类的属性,此时的子类的属性与父类就没关系了,相当于新定义了一个子类的属性
- 属性的覆盖是没多大意义的
- 请解释super和this的区别
- 在程序类中使用this表示先从本类查找所需的属性或方法,如果本类不存在则查找父类定义,如果使用super则表示不查找子类,直接查找父类
- this与super都可进行构造方法的调用,this调用的是本类构造,super调用的是由子类调用父类构造,因为两个都需放构造方法的首行,所以不能同时出现
- this可以表示当前对象。
- final关键字
- final在程序中描述的是终结器的概念,java中使用final关键字可以实现如下功能:
- 定义不能够被继承的类
- 不能被覆写的方法、常量
final class Channel{} //这个类不能有子类 class DatabaseChannel extends Channel {} //错误的继承
- 当子类继承父类,如父类不希望自己的方法被子类覆写,则使用final进行修饰
class Channel{ public final void conect(){} //此方法不能被覆写 } class DatabaseChannel extends Channel { public void connect(){} //错误 }
- 底层设计会涉及到final关键字修饰
- 在final关键字有个重要的应用技术:可以利用其定义常量,常量的内容一旦定义则不可修改
-常量往往是公共的定义,为了可以体现共享的概念会用public static final int ON = 1;
这种去修饰全局常量 - 定义全局常量,每一个字母必须大写
public class StringDemo{ public static void main(String args[]){ final String info = "baidu"; String strA="www.baidu.com"; String strB="www." + info + ".com"; System.out.println(strA==strB); //返回true,如果info不用final修饰,则返回false } }
- final在程序中描述的是终结器的概念,java中使用final关键字可以实现如下功能:
Annotation注解
- Annotation简介
- 是jdk1.5后提出的开发技术结构,理用Annotation可以有效减少程序配置的代码,并可理用Annotation进行结构化定义。
- Annotation是以注解的形式实现的程序开发
- 注解可以减少配置文件的数量
- 准确的覆写:@Override
- 开发中经常出现的问题:
- 在进行覆写时,会忘记子类集成父类的extends关键字
- 在进行方法覆写时,单词拼错,但是程序编译时是不会出错的,执行时会发现不正确
- 为避免以上问题出现,可以在明确覆写方法上追加有一个注解@Override,表示该方法是覆写来的方法,帮助开发者在编译时就暴露以上问题。
- 开发中经常出现的问题:
- 过期注解
- 在软件项目迭代开发中,可能有某个方法某个类,由于最初设计时考虑不周(存有缺陷)导致新版本应用会有不适应的地方,老版本不影响,此时不好直接删除这个操作,给个过渡时间,给个过期声明,告诉新用户不用了。
- @Deprecated 注解
- 压制警告@SuppressWarning
- 以过期注解为例,在编译时会有报错
注:xxx.java使用或覆盖了已过时的API。 注:有关详细信息,请使用-Xlint:deprecation 重新编译
如果此时不愿意见到这些提示信息(或已经明确的知道了错误在哪里),就可以进行错误警告信息的压制
- 让警告信息在编译的时候不出现而已
- 以过期注解为例,在编译时会有报错
多态
- 多态性简介
- 面向对象中的第三大特性
- 是在继承的基础上扩展出来的概念,实现父子类之间的互相转换处理
- 两种实现模式
- 方法的多态性
- 方法的重载:同一个方法名称根据传入的参数类型或个数的不同实现不同功能的执行
- 方法的覆写:同一个方法可能根据子类的不同有不同的实现
- 对象的多态性:父子实例之间的转换处理
- 对象向上转型:父类 父类实例 = 子类实例;自动完成转换
- 对象的向下转型:子类 子类实例 = (子类)父类实例 ; 强制完成转换
- 从实际考虑,大部分情况下考虑对象的向上转型(95%),对于对象的向下转型,在使用子类特殊功能的时候采用向下转型
- 方法的多态性
- 对象向上转型(接收后返回参数的统一性)
Animal an = new Person();
人是动物,向上转型- 向上转型的用处:可以对参数进行统一的设计
class Message{ public void print(){ System.out.println("Message连接信息"); } } class DataBaseMessage extends Message{ public void print(){ System.out.println("DataBase连接信息"); } } class WebServerMessage extends Message{ public void print(){ System.out.println("WebServer连接信息"); } } public class JavaDemo{ public static void main (String args[]){ fun(new DataBaseMessage()); //向上转型 fun(new WebServerMessage()); //向上转型 } public static void fun(Message msg){ msg.print(); } }
- 对象向下转型
- 向上转型描述的是一些公共特征,向下描述的是子类的特殊的定义。
- 向下转型并不安全,因为在进行向下转型之前,一定要首先发生向上转型
class Person{
public print(){
System.out.println("吃饭睡觉打豆豆");
}
}
class SuperMan extends Person{
public String fly(){
return "I can fly ...";
}
public String fire(){
return "I can fire ...";
}
}
public class JavaDemo{
public static void main(String args[]){
System.out.println("正常情况下超人是普通人。");
Person per = new SuperMan(); //向上转型
per.print();
System.out.println("怪兽来了超人出动。");
SuperMan man = (SuperMan) per; //向下转型
System.out.println(man.fly());
System.out.println(man.fire());
}
}
- instanceof 关键字
- 判断某个实例是否是某个类的对象
对象 instanceof 类
返回boolean- 之后进行向下转型,要先通过instanceof先判断一次
Object类
- Object类基本概念
- java中只有Object类是不存在继承关系的,所有的类都是Object的子类
class Person{} class Person extends Object{} //两种写法意义相同
- 如果一个程序的方法要求可以接收所有类的对象的时候,可以利用Object类实现处理;需要注意:对于所有的引用数据类型都可以使用Object类进行接收,包括数组
- Object是万能数据类型,更适合于程序的标准设计
- java中只有Object类是不存在继承关系的,所有的类都是Object的子类
- 获得对象信息 toString()
- toString()方法可以获取一个对象的完整信息
class Person{} public class JavaDemo{ public static void main(String args[]){ Person per = new Person(); System.out.println(per); System.out.println(per.toString()); //Objetc类继承而来 //两个输出语句输出内容相同 } }
- 对象直接输出时所调用的toString()方法,调与不调是一样的
- 后面在写简单java类时,可以使用重写toString()方法来替代getinfo()方法
- 对象比较 equals()
- 比较两个对象的内容是否相同
- Object的equals()方法,默认情况下只是做了两个对象的内存地址的判断,没进行内容的判断
- 对于开发者而言,如果要正确实现判断处理,则要在子类中覆写此方法,并进行属性比较
抽象类定义及使用
- 抽象类的基本概念
- 为什么要使用抽象类
- 程序可以通过继承来实现子类覆写父类的方法,但是不好强制子类去覆写,在实际开发中很少会继承一个已完善的类
- 而必须实现抽象类,在父类设计,优先考虑设计为抽象类
- 抽象类定义
- 对子类中覆写方法进行约定
- 抽象类用abstract关键字来定义
- 抽象方法用abstract关键字来修饰
- (即,在普通类基础上追加抽象方法就是抽象类)
- 定义一个抽象类
abstract class Message{ //定义抽象类,不是完整的类 private String type; public abstract String getConnectInfo(); //抽象方法没有大括号 public void setType(){ //普通方法 this.type = type; } }
- 抽象类是不能用关键字new 的,不能实例化
- 抽象类必须提供有子类,用extends继承抽象类
- 抽象类的子类,一定要覆写抽象类中的所有抽象方法
- 抽象类的对象实例化,可以利用对象多态性通过子类实例向上转型的方式完成
- 为什么要使用抽象类
- 抽象类的相关说明
- 不能用final定义抽象类,因为final修饰的不能又子类,而抽象类是需要有子类的
- 抽象类一定有提供构造方法,并且子类也会按照子类的实例化原则调用构造
- 抽象类中允许没有抽象方法,即便没有抽象方法,也无法使用new直接实例化抽象类对象
- 抽象类中可以提供static方法,该方法不受抽象类对象的局限
包装类
- 包装类实现原理分析
- 包装类主要功能,是针对基本数据类型的对象转换而实现的,并且随着JDK版本的更新,包装类也有更多功能支持
- 认识包装类:
- Object类最大特点是所有类的父类,并可以接收所有数据类型,此过程中存在一个问题:基本数据类型并不是类,所以现在要想将基本数据类型以类的形式进行处理,就需要对其进行包装
class Int{ private int data ;//包装了一个基本数据类型 public Int(int data){ this.data = data ; } public int intValue() { return this.data; } } public class JavaDemo { public static void main(String args[]) { Object temp = new Int(10); //装箱:将基本数据类型保存在包装类之中 int x = ((Int)temp).intValue(); //拆箱:从包装类对象中获取基本数据类型 }
基本数据类型进行包装处理后,可以像对象一样进行引用传递,同时也可以使用Object类来进行接收
- 基本数据类型一共有8种,这8中包装类的基本定义如下:
- 包装类一共提供两种类型,
- 对象型包装类(Object直接子类):Boolean 、Character
- 数值型包装类(Number直接子类):Byte、Short、Float、Double、Integer、Long
方法名称 类型 描述 public byte byteValue() 普通 从包装类中获取byte数据 public short shrtValue() 普通 从包装类中获取short类型数据 public abstract int intValue() 抽象 从包装类中获取int类型数据 public abstract long longValue() 抽象 从包装类中获取long类型数据 public abstract float floatValue() 抽象 从包装类中获取float类型数据 public abstract double doubleValue() 抽象 从包装类中获取double类型数据
- 装箱与拆箱
- 基本数据类型包装类为了基本类型转为对象所提供的
- 数据装箱:将基本数据保存到包装类之中,一般可利用构造方法来完成
- 拆箱:从包装类中获取基本数据类型
- 数值型包装类已经由Number类定义了拆箱的方法了
- Boolean型:public boolean booleanValue();
- 从jdk1.9之后,所有包装类中提供的装箱拆箱操作被废弃了,9之后进行自动装箱拆箱
- 观察自动装箱拆箱
public class JavaDemo { public static void main(String args[]){ Integer obj = 10; //自动装箱 int num = obj ; //自动拆箱 obj ++ ; //直接参与数学运算 System.out.println(num * obj); //直接参与数学运算 } }
除了提供自动数学运算的支持外,自动装箱还可实现Object自动接收基本数据类型的操作
- 进行包装了相等判断,要使用equals()比较
接口的定义与使用
- 接口的基本定义
当可以灵活的使用接口和抽象类进行程序设计时,面向对象的基本概念就理解了;需要大量的程序代码累积来达到- 什么叫接口
接口可以理解为最纯粹的抽象类(最原始的接口定义中只包含抽象方法和全局常量) - 接口定义:interface修饰
interface IMessage { public static final String INFO = "www.baidu.com"; // 全局常量 public abstract String getInfo(); //抽象方法 } interface IChannel { public abstract boolean connect(); //定义抽象方法 } class MessageImpl implements IMessage,IChannel{ //实现了多个接口接口 public String getInfo(){ return "实现抽象方法了"; } public boolean connect(){ return true; } }
- 接口需要被子类实现(implements),一个子类可实现多个父接口
- 子类如果不是抽象类,一定要覆写接口之中的全部抽象方法
- 接口对象可以利用子类对象的向上转型进行实例化
- 先继承,再实现
- 虽然接口无法继承一个父类,但是一个接口可以实现若干个父接口,可以通过extends继承若干个父接口,此时称为接口的多继承
interface IMessage { public abstract String getInfo(); //抽象方法 } interface IChannel { public abstract boolean connect(); //定义抽象方法 } //extends在类继承上只能继承一个,但接口可以继承多个 interface IService extends IMessage,IChannel { //接口多继承 public abstract String service(); } class MessageService implements IService{ public String geiInfo(){ return "获取信息"; } public boolean connect(){ return true; } public String service(){ return "获取消息服务"; } }
- 虽然接口无法继承一个父类,但是一个接口可以实现若干个父接口,可以通过extends继承若干个父接口,此时称为接口的多继承
- 在实际开发中,接口使用有三种形式
- 进行标准设置;
- 表示一种操作的能力;
- 暴露远程方法视图,这个一般在RPC分布式开发中使用。
- 什么叫接口
- 接口定义加强
- 场景:定义个一个接口被1080个子类实现,此时要在接口中追加一个方法
- 最早的方案jdk1.8之前:结构设计不当导致的结果,为方便子类修改,往往不会直接让子类实现接口,中间会加个过渡的抽象类
- jdk1.8之后:接口中允许开发者定义普通方法
- 普通方法定义
接口中的普通方法必须加上default的声明,该方案属于挽救功能,不能作为设计首选。
除了追加普通方法外,接口理可以定义static方法,static可以通过接口直接调用
- 普通方法定义
- 场景:定义个一个接口被1080个子类实现,此时要在接口中追加一个方法
- 使用接口定义标准
- 工厂设计模式 factory
-
代理设计模式 Proxy
-
抽象类与接口的区别
No. | 区别 | 抽象类 | 接口 |
---|---|---|---|
1 | 定义 | abstract class 抽象类名称{} | interface 接口名称{} |
2 | 组成 | 构造、普通、静态方法、全局常量、普通成员、static方法 | 抽象方法、全局常量、普通方法、static方法 |
3 | 权限 | 可以使用各种权限定义 | 只能使用public |
4 | 子类使用 | 子类可以使用extends关键字集成抽象类 | 子类使用implements实现多个接口 |
5 | 两者关系 | 抽象类可以实现若干个接口 | 接口不允许继承抽象类,但是允许继承多个父接口 |
6 | 使用 | 1、抽象类或接口必须定义子类;2、子类一定要覆写抽象类或接口中的全部抽象方法;3、通过子类的向上转型实现抽象类或接口对象的实例化 | |
程序设计,最先是从接口开始,再到抽象类,最后设计具体的类
泛型
内部类
- 存在意义:方便的访问外部类中的私有属性
- 内部类是一种非常灵活的结构,只要语法满足
函数式编程
- Lambda表达式
- 在一个接口中只提供一个方法,除此之外没有任何其他方法,这样的接口称为函数式接口,只有函数式接口才可以被Lambda表达式所使用
```java
@FunctionalInterface //函数式接口
interface IMessage {
public void send(String str) ;
}
public class JavaDemo {
public static void main (String args[]){
IMessage msg = (str) -> {
System.out.println("发送消息: "+str);
};
msg.send("www.baidu.com");
}
}
··· -
Lambda有如下几种表达格式:
- 方法没有参数: () -> {};
- 方法有参数: (参数,参数) -> {} ;
- 如果现在只有一行语句返回:() -> 语句;
- 在一个接口中只提供一个方法,除此之外没有任何其他方法,这样的接口称为函数式接口,只有函数式接口才可以被Lambda表达式所使用
- 方法引用
- 引用静态方法: 类名称 :: static 方法名称;
- 引用某个实例对象的方法:实例化对象 :: 普通方法;
- 引用特定类型的方法: 特定类 :: 普通方法;
- 引用构造方法: 类名称 :: new
@Auther:ZhuChun