怎吗做网站挣钱,网站优化外包费用,住建局官网平台,免费做网站广告第三章 数据类型和运算符
Java语言是强类型语言#xff0c;意思是每个变量和每个表达式都有一个在编译时就确定的类型#xff0c;所有的变量都必须显式声明类型
标识符就是类#xff0c;变量、方法命名的符号
标识符不能包含空格
标识符只能包含美元符($)#xff0c;不…第三章 数据类型和运算符
Java语言是强类型语言意思是每个变量和每个表达式都有一个在编译时就确定的类型所有的变量都必须显式声明类型
标识符就是类变量、方法命名的符号
标识符不能包含空格
标识符只能包含美元符($)不能包含其他特殊字符
java关键字都是小写
基本数据类型(单位字节)
1 - byte
2 - short
4 - int
8 - long
2 - cchar
4- flaot
8-double
1-boolean
如果使用一个巨大的整数常量(超出int类型的范围)java不会自动把这个整数常量当成long类型来处理
字符集
什么时字符集
严格来说计算机无法保存电影、音乐、字符计算机只能保存二级制码因此这些东西要先转换成二进制码才能保存 所以才会出现各种各样的格式——mp3,wna之所以需要这些格式是用来将这些文件转换为二进制码才能保存。对于保存字符就简单多了直接把所有需要保存的字符编号当计算机要保存某个字符时只要将该字符的编号转换为二进制码然后保存起来。所谓字符集就是给所有字符的编号组成组合。早期美国人给英文字符、数字、标点符号等字符进行了编号让们认为所有字符顶多100多个这就是ASCII字符集后来其他国家的加入美国人又为这些语言的字符进行统一编号这次他们用了2字节16位支持65536个字符编号,这就是Unicode字符集。 字符型值的三种表示形式
//直接通过单个字符来指定字符型值char c A;
//通过转义字符表示特殊字符型值
char a \n;
//直接使用Unicode值来表示字符型值格式时\uXXXX,其中XXXX代表一个十六进制的整数
public class CharTest{
public static void main(String[] args){
char c 97;
System.out.println(c);//会直接打印字母a,这个是在ASCII字符集中的
}
}
如果把0-65535范围内的一个int整数赋给char类型系统会自动把这个int整数当作char类型来处理
还是记忆一下转义字符
\b -退格符
\n -换行符
\r-回车符
制表符的功能是在不使用表格的情况下在垂直方向按列对齐文本
\t是制表符如果前面输出的内容是8的倍数则\t将输出8个空格如果不是则补齐为8的倍数。
\t-制表符
Java7引入的新功能:程序员可以在数值中使用下划线不管是整数数值还是浮点型数值
//字符串true和false不会直接转换成boolean类型但如果直接使用一个boolean类型的值和字符串进行连接运算则boolean类型的值会自动转换成字符串
String str true ;
System.out.println(str); 3.4.6 使用var定义变量
使用var定义局部变量时必须在定义局部变量的同时指定初始值否则编译器无法推断该变量的类型
var a 20;
System.out.println(a);
var b3.4;
System.out.println(b);
var c (byte)13;
System.out.println(c);
REMEMBER ME day 3 10.12
float a (float)5.6//如果没有float是不行的因为double的字节比float的字节大//5.6系统默认是double
在一般情况下字符串不能转换为基本类型但通过基本类型对应的包装类可以实现把字符串转换为基本类型
String a 45;
int iValue Integer.parseInt(a); 3.5.3 表达式类型的自动提升
当一个算数表达式包含了多个基本类型的值整个算数表达式的数据类型将发生自动提升。
Java定义了一些规则
1.所有的byte类型、short类型和char类型都将被提升到int类型
2.等号右边的类型必须小于左边的类型 如果表达式中包含了字符串这个加号时一个字符串连接运算符而不是进行加法运算
System.out.println(a7hello);
//我们来分析一下 a7会转化为int,那么就是977 104
//104hello就变成字符串的连接运算 3.6直接量
直接量就是通过源代码直接给出的值int a 5;
3.6.1直接量的类型
能指定直接量的通常只有三种类型基本类型字符串类型和null类型。
识记内容
0b/0B是二进制开头的 ➢ long类型的直接量在整型数值后添加l或L后就变成了long类型的直接量。例如3L、0x12L对应十进制的18L。 ➢ float类型的直接量在一个浮点数后添加f或F就变成了float类型的直接量这个浮点数可以是标准小数形式也可以是科学计数法形式。例如5.34F、3.14E5f。 ➢ double类型的直接量直接给出一个标准小数形式或者科学计数法形式的浮点数就是double类型的直接量。例如5.34、3.14E5。 ➢ boolean类型的直接量这个类型的直接量只有true和false。 ➢ char类型的直接量char类型的直接量有三种形式分别是用单引号括起来的字符、转义字符和Unicode值表示的字符。例如a、\n和\u0061。 ➢ String类型的直接量一个用双引号括起来的字符序列就是String类型的直接量。 ➢ null类型的直接量这个类型的直接量只有一个值即null。 关于字符串直接量当程序第一次使用某个字符串直接量时Java会使用常量池来缓存该字符串直接两如果程序后面的部分需要用到该字符串直接量的时候Java会直接使用常量池中的字符串直接量
常量池
常量池指的是在编译期被确定并被保存在已编译到达.class文件中的一些数据。它包括关于类、方法、接口中的常量也包括字符串直接两
String a hello;
String b hello;
String c
10.14
3.7 运算符
/:除法运算符如果两个操作数中有一个是浮点数或者两个都是浮点数这个结果就是自然除法的结果。而且此时除法是0或者0.0得到的结果就是正无穷大或负无穷大
public class DivTest{public static void main(String[] args){double a 5.2;double b 3.1;double div a/b;//div的值将是1.6774193548387097System.out.println(div);//输出正无穷大InfinitySystem.out.println(5除以0.0的结果是: 5 / 0.0);//输出负无穷大-InfinitySystem.out.println(-5除以0.0的结果是: - 5 / 0.0);//下面代码将出现异常//java.lang.ArithmeticException: / by zeroSystem.out.println(-5除以0的结果是:: -5 / 0);}} Infinity:无限
%:
同样的道理如果求余运算中两个操作数中有一个或两个是浮点数则允许第二个操作数是0/0.0
求余结果是非数NaN public class ModTest{public static void main(String[] args){double a5.2;double b3.1;double moda % b;//mod的值为2.1System.out.println(mod);//输出非数NaNSystem.out.println(5对0.0求余的结果是: 5 % 0.0);//输出非数NaNSystem.out.println(-5.0对0求余的结果是: -5.0 % 0);//输出0System.out.println(0对5.0求余的结果是: 0 % 5.0);//输出非数NaNSystem.out.println(0对0.0求余的结果是: 0 % 0.0);//下面代码将出现异常//java.lang.ArithmeticException: / by zeroSystem.out.println(-5对0求余的结果是: -5 % 0);}} :自加
注意下面这段代码 int a5;//让a先执行算术运算然后自加int ba 6;//输出a的值为6b的值为11
//首先执行算数表达式5611System.out.println(a \n b);
3.7.3 位运算符
:按位与
I:按位或
~按位非
^:按位异或
当两个操作数不同时才返回true如果两个操作数相同则返回false。 无符号右移运算符 感觉唯一需要注意的就是 0^0 0
1^1 0 比较运算符 :如果进行比较的是两个数值类型即使他们的数据类型不相同只要值相同返回true
97 a;
5.0 5;
//这两个都是true
ture false;
//返回false这个是允许的 但如果两个是引用类型那么只有当这两个引用变量引用相同类的实例时才可以比较而且这两个引用必须指向同一个对象才可以返回true 使用javadoc来编写一个api程序
/**
* author xzc
* version jdk1.8.0
*/public class apiTest{
/*** 求输入两个参数范围以内整数的和* param n 接收的第一个参数* param m 接收的第二个参数* return 两个参数范围以内整数的和*/
public int add(int n,int m){
int sum 0;
for(int i 0;im;i){
sum sum * i;
}
return sum;
}
}
使用单行、多行和文档注释说出他们分别适用于哪里。完整的使用出javadoc的所有属性。 单行注释短的注释没什么要求 多行注释长的注释没什么要求 文档注释分为3种 1类注释要求放在类的前面常用author、version 2方法注释要求放在方法前面常用param、return 3变量注释要求放在成员变量前面 , 并不会在文档中显示不知道为什么 5、在java文档注释里使用html5的规范。还挺好用
6、javadoc对类文件生成文档看看public以外的外部类会不会生成文档。不会只有public类才会 所以要把java文件分开写一个类一个文件再测试一下生成包文档只要放在一个文件下就只会生成public类的文档
7、说出标识符的命名规则 第一要能够看懂 第二不要乱用特殊符号 第三尽量简洁 具体规则 不能由数字开头 不能是java的关键字 不能包含空格 只能包含$和_这两种特殊符号和字母、数字其他都不行
8、说出java的基本数据类型有哪些以及他们分别是多少字节 char 2字节 byte 1字节 short 2字节 int 4字节 long 8字节 float 4字节 double 8字节
switch语句
使用switch语句时有两个值得注意的地方
第一个地方是switch语句后的expression表达式的数据类型只能是byte、short、char、int四个整数类型和枚举类型String属于引用类型
第二个地方是如果省略了case后代码块的break将引入一个陷阱 10.15
4.5.1定义数组
int[]是一种数据类型一样可以使用该类型来定义变量也可以使用该类型进行类型转换等
所以我们呢也推荐这样一种写法格式
type[] arrayName;
type arrayName[];//我们一般先写变量类型再写变量名 4.5.3 数组的初始化
所谓初始化就是为数组的数组元素分配空间并为每个数组元素赋值 能不能只分配内存空间不赋值 不行一旦为数组的每个数组元素分配了内存空间每个内存空间里存储的内容就是该数组元素的值即使这个内存 空间存储的内容是空null)。
其实它在分配内存空间的时候就已经赋值了这个是系统的动态初始化
null也是初始值
只要为数组元素分配了内存空间数组元素就具有初始值。
初始值的获得由两种形式一种由系统自动分配另一种由程序员指定 数组初始化的两种方式
静态初始化初始化时由程序员显式指定每个数组元素的初始值由系统决定数组长度
//eg:
int[] a {5,6,7,8};//不需要new int
动态初始化初始化时程序员只指定数组长度其实就是指定内存由系统为数组元素分配初始值
Object[] book new String[4];
➢ 数组元素的类型是基本类型中的整数类型byte、short、int和long则数组元素的值是0。 ➢ 数组元素的类型是基本类型中的浮点类型float、double则数组元素的值是0.0。 ➢ 数组元素的类型是基本类型中的字符类型char则数组元素的值是\u0000。 ➢ 数组元素的类型是基本类型中的布尔类型boolean则数组元素的值是false。 ➢ 数组元素的类型是引用类型类、接口和数组则数组元素的值是null var a1 new String[] {xiaoming,daxioong};
//要指定相关初始值
var a2 {5,6,7,8};//error var无法知道类型 如果访问数组元素时指定的索引值小于0或者大于等于数组的长度编译程序不会出现任何错误但运行时出现异常java.lang.ArrayIndexOutOfBoundsExceptionN数组索引越界异常异常信息后的N就是程序员试图访问的数组索引。 4.6.1 内存中的数组 识记的数组对象被存储在堆内存中如果引用该数组对象的数组引用变量时一个局部变量那么它被存储在栈内存中
public class ArrayInRam{public static void main(String[] args){//identify and initialize the array,static initialint[] a [5,7,20];//var 动态初始化var b new int [4];for(var i:b){System.out.pritln(i);}//因为两者都是int类型数组可以使b指针指向a指针System.out.println(b数组的长度b.length);System.out.println(a数组的长度:a.length);b a ;System.out.println(b指向a数组后的长度b.length);}
} 4.6.3
引用数组的初始化
引用类型数组的数组元素是引用
既可以直接作为值基本数据类型也可以作为引用引用类型指向其他具体值
class Person
{public int age;public double height;//info 是信息的意思pubic void info(){System.out.println(My age is age My height is height); }
}
public class ReferenceArrayTest
{public static void main(String[] args){//initialize and identifyPerson[] students new Person[2];//invite two examplevar zhang new Person();zhang.age 18;zhang.height 180;var xu new Person();xu.age 18;xu.height 172;students[0] zhang;students[1] xu;//下面两行代码结果一样因为指向的是相同的xu.info();students[1].info();}
} 4.6.4 没有多维数组
type[][] arrname new type[length][];
//相当于定义了length个type[]类型的变量
public class TwoDimensionTest
{public static void main(String[] args){//定义一个二维数组int[][] a;//将a当成一维数组来处理a new int[4][];for(int i 0,len a.length;ilen;i){System.out.println(a[i]);}//initialize a 数组的第一个元素a[0] new int[2];a[0][1] 6;//a数组的第一个元素是一个一维数组for(int i 0,lena[0].length;ilen;i){System.out.println(a[0][i]);}}
} 这里最重要的是将第一个元素当成一个数组 //use static initialization to initialize
String[][] str1 new String[][]{new String[3],new String[]{hello}};
//使用简化静态初始化方法
String[][] str2 {new String[3],new String[]{hello}};二维数组是一维数组其数组元素是一维数组三维数组也是一维数组其数组元素是二维数组……从这个角度来看Java语言里没有多维数组。 4.6.5 操作数组的工具类Arrays
因为Arrays中有大量的static方法可以直接使用
注意点
使用二分查找需要保证数组的大小是从小到大
equals方法只是保证数组之间的长度和元素相同不是保证地址 10.16 第五章 面向对象 (上)
5.1.1 定义类
{修饰符} class 类名
{零到多个构造器定义……0到……成员变量0到……方法
} 定义成员变量的语法格式
{修饰符} 类型 成员变量名 [默认值]
修饰符可以省略也可以是public,protected,private,static,final,其中public ,protected,private三个最多只能出现其中一个可以与staticfinal组合起来修饰成员变量
类型基本类型和引用类型只要java允许
成员变量名骆驼命名法 定义方法语法格式
[修饰符] 方法返回值类型 方法名(形参列表)
{//零到多条执行语句组成的方法体
}
修饰符
修饰符可以省略也可以是public、protected、private、static、final、abstract其中public、protected、private三个最多只能出现其中之一abstract和final最多只能出现其中之一它们可以与static组合起来修饰方法。
方法返回值类型
返回值可以是java允许的任何返回类型
必须使用void来声明没有返回值 static 是一个特殊的关键字它可用于修饰方法、成员变量等成员。static修饰的成员表明它属于这个类本身而不属于单个实例因此通常把static修饰的成员变量称为类变量、类方法可以直接调用不需要创建对象
不使用static修饰的普通方法成员变量则属于该类的单个实例而不属于该类。因为通常把不使用static修饰的成员变量和方法也成为实例变量和实例方法(需要对象才可以调用) Attention:
static的真正作用是用于区分成员变量、方法内部类、初始化块 构造器是一个特殊的方法定义构造器的语法格式与定义方法的语法格式很想
{修饰符} 构造器名(形参列表)
{
//由0——多条可执行语句组成的构造器执行体
}
修饰符修饰符可以省略省略自动为public
ATTENTION:
构造器没有返回类型如果为构造器定义了返回值类型或使用void声明构造器没有返回值编译时不会出错但java会把这个所谓的构造器当作方法来处理
构造器返回的是类的实例不能在构造器里显式使用return来返回当前类的对象因为构造器的返回是隐式的 5.1.2 对象的产生和使用
创建对象的根本途径是构造器通过new关键字来调用某个类的构造器即可创建这个类的实例
var p new Person();
//使用var可以提高简洁性
java对象的作用
访问对象的实例变量
调用对象的方法
5.1.3 对象、引用和指针
Person p new Person()
这行代码产生了两个东西一个是变量p,一个是对象Person
Person对象含有两个变量变量需要内存来存储的 Person对象由多块内存组成不同内存块分别存储了Person对象的不同成员变量当把这个Person对象赋给一个引用变量p时会让引用变量直接指向这个对象。也就是说引用变量里存放的仅仅是一个引用它指向实际的对象 堆内存里的对象可以有多个引用即多个引用变量指向同一个对象
var p2 p;//将p变量保存的地址值赋给p2变量
如果希望通知垃圾回收期回收某个对象只需切断该对象的所有引用变量和它之间的关系即可 5.1.4 对象的this引用
this关键字指向调用该方法的对象
public class DOg{
public void jump(){
System.out.println(正在执行jump方法)
}
public void run(){
jump();
System.out.println(正在执行run方法);
}
}
//一般来说如果调用static修饰的成员包括方法、成员变量时省略了前面的主调那么默认使用该类作为主调如果调用没有static修饰的成员包括方法、成员变量时省略了前面的主调那么默认使用this作为主调。ATTENTION:
在Java中我们应尽量使用类名来调用static方法虽然对象也可以使用static方法 5.2 方法详解 方法类似于函数但是java中方法不能单独存在方法在逻辑上属于类要么属于对象。
5.2.1 方法的所属性
方法与传统的函数有着显著的不同
在结构化编程语言中函数是一等公民整个软件由一个个函数组成。
但是在面向对象编程语言中类才是一等公民整个系统由一个个的类组成。 10.17
5.2.2方法的参数传递机制
调用方法时
Java中参数传递方式只有一种值传递就是将实际参数值的副本传入方法内而参数本身不会受到任何影响
传入方法的实际参数值的复制品不管方法中对这个复制品如何操作实际参数值本身不会受到任何影响 //primitive 粗糙的
public class PrimitiveTransferTest
{public static void swap(int a,int b){var tmp a;a b; b tmp;System.out.println(In method of swap:the value a is a\n The value b is b);}public static void main(String[] args){var a 6;var b 9;swap(a,b);System.out.println(After transfering,the va isa\n vb is b);}
} 当程序执行swap()method系统进入swap()方法并将main()方法中的a、b变量作为参数值传入swap()方法传入swap()方法只是a、b副本而不是a,b本身 下面看一个容易搞混的点传入引用变量 堆内存中保存了对象本身栈内存中保存了引用该对象的引用变量 系统复制的时dw变量而不是对象本身
变量是用来指向变量的指针
5.2.3 形参个数可变的方法
形参个数可变的参数本质就是一个数组参数
public static void test(int a,String...books)
//equals
public static void test(int a,String[] books)
区别是调用两个方法存在区别
第一种方法可以直接
test(5,a,b);
//第二中method
test(5,new String[]{a,b});
个数可变的形参只能处于参数列表的最后。一个方法最多只包含一个个数可变的形参。个数可变的形参本质上是一个数组类型的形参。因此调用包含个数可变形参的方法时该个数可变的形参既可以传入多个参数也可以传入一个数组。
######
5.2.5 方法重载
Java允许同一个类里定义多个同名方法只要形参列表不同就行。如果同一个类中包含两个或两个以上方法名相同但形参列表不同则被称为方法重载。 方法重载的要求就是两同一不同同一个类中方法名相同参数列表不同。至于方法的其他部分如方法返回值类型、修饰符等与方法重载没有任何关系。 5.3 成员变量和局部变量 成员变量指的是在类中定义的变量也就是field
局部变量指的是在方法里定义的变量 一个类在使用之前要经过类加载、类验证、类准备、类解析、类初始化等几个阶段
类变量可以理解为类成员变量与类本身共存亡
实例变量与实例共存亡
实例.类变量实例.实例变量实例.类变量 局部变量根据定义形式的不同又被分为三种
形参在定义方法签名时定义的变量形参的作用域在整个方法内有效
方法局部变量从定义该变量的地方生效到该方法结束时生效
代码块局部变量从定义该变量的地方生效到该代码块结束时生效
5.3.2 成员变量的初始化和内存中的运行机制
当系统加载类或创建该类的实例时系统自动为成员变量分配内存空间并在分配内存空间后自动为成员变量指定初始值。 var p1 new Person();
var p2 new Person();
p1.name Jack;
p2.name John;
p1.eyeName 2;
p2.eyeName 3;当程序执行第一行代码var p1new Person();时如果这行代码是第一次使用Person类则系统通常会在第一次使用Person类时加载这个类并初始化这个类。在类的准备阶段系统将会为该类的类变量分配内存空间并指定默认初始值。
当Person类初始化完成后系统内存中的存储示意图如图5.10所示。 10.18
5.3.3 局部变量的初始化和内存中的运行机制
这里要注意一下
public static void main(String[] args){
int a;//这也是局部变量因为这也是一个方法修饰符是public static
}
局部变量只有赋值了系统才会给他内存
局部变量总是保存在其所在方法的栈内存中。如果局部变量是基本数据类型的变量则直接把这个变量的值保存在该变量对应的内存中如果局部变量是一个引用类型的变量则这个变量里存放的是地址通过该地址引用到该变量实际引用的对象或数组 栈内存中的变量无需垃圾回收器回收往往随着方法或代码块的运行结束而结束 5.3.4 变量的使用规则
考虑使用成员变量
1.固有信息-身高每个人不同但都有这么一个属性
2.类相关信息-眼睛的数量大部分人有两只眼睛这种一般不会改变的可以修改成类变量
3.状态信息-五子棋的棋盘数组
4.共享信息
5.4 隐藏和封装
封装的作用这里了解一下就行
➢ 隐藏类的实现细节。 ➢ 让使用者只能通过事先预定的方法来访问数据从而可以在该方法里加入控制逻辑限制对成员变量的不合理访问。 ➢ 可进行数据检查从而有利于保证对象信息的完整性。 ➢ 便于修改提高代码的可维护性。 为了实现良好的封装需要从两个方面考虑。 ➢ 将对象的成员变量和实现细节隐藏起来不允许外部直接访问。 ➢ 把方法暴露出来让方法来控制对这些成员变量进行安全的访问和操作 5.4.2 使用访问控制符
private:封装专用于修饰成员变量
default:在同一个包中
protected:子类也可以使用通常用于要被继承的方法
public:被所有类访问
外部类只有两种public 和 default 因为外部类没有在任何类的内部 一个类就是一个小的模块要尽量避免一个类和另一个类发生相关联系
高内聚(将模块中的内部数据、功能实现的隐藏细节给英藏起来)和低耦合(尽暴漏少量的方法给外部使用) 关于访问修饰符的使用存在如下规则
1.有些方法只用于辅助实现该类的方法也应该使用private 5.4.3 package、import和import static
在工作场合中会出现一些同名类的情况这个时候包的出现可以有效的解决类的命名冲突更方便我们找到我们需要的类文件
一旦源文件中使用了package语句意味着该源文件中所有的类都属于这个包
操作系统在编译源文件的时候会自动建立一个包这个包里面有我们写的类文件
这是因为Java规定位于包中的类在文件系统中也必须有余包名层次相同的目录结构 package lee;
public class Hello{public static void main(String[] args){System.out.println(我爱java);}
}
一个文件夹用于存放源文件一个用来存放类文件 为Java指定包名并不是由目录决定是由我们编写的代码所决定的package 包名
包名应该全部是小写字母而且是多个有意义的单词连缀而成的
为了避免不同公司之间类名的重复Oracle建议使用公司Internet域名倒写来作为包名
eg:Internetcrazyit.org - org.crazyit
在实际企业开发中还会在org.carzyit包下面建立各种自爆
如果项目足够大还会在项目名子包中建立模块子包反正一直到底层就对了
一个源文件只有一条package语句 为了在之后的编程中引用其他包下面的类没有那么繁琐我们可以在开头引入指定包层次下的某个类或全部类 //import 语句应该出现在package语句之后、类定义之前
package lee;
//导入指定类
import package.subpackage...ClassName;
//导入全部类
import package.subpackage...*; Attention:
Java serve all the file java that they all autonomic have java.lang all the classes
About Date.class
If you want to use class Date,please dont import java.sql and java.util at the same time,because they all have Date.classor it will result into chaos(混乱的) in system After JDK 1.5 . We can lead to certain class single static variable,method and all static variable
//The syntax for importing all static member variables and methods of a specified class is as follows:
//This sentence is meant to import static member variable and static method called methodName
import static package.subpackage...ClassName.fieldName|methodName;// The syntax for importing all the static variables and method of specified class is as follows:
import static package.subpackage...ClassName.*;
//* only can symbolize the static member variable and method 10.19 5.4.4 Java package that in common use
java.lang:include corn class of Java
java.util:A large of tool/接口和集合框架类-Arrays and List
java.net:include class/API about Internet programme
java.io:include class/API about input/output
java.text:java formatting(格式化)
java.sql:structurct of JDBC
java.awt: class/API about Abstract Window Toolkits
java.swing:include Swing 图形用户界面编程GUI程序 5.5 deep into constructor
The class of Java must include one or more than one constructor 5.1 Use constructor to initialize If programmer dont provide any constructor to Java class,system will provide a constructor that dont have parameter If constructor B about constructor A. We can use this keyword 5.6 The inherit of class
Every class only have one straight parent class.(single inherit)
5.6.1 The characteristic of inherit
By extend扩展的意思
被继承的类称为父类、超类、基类
从子类的角度来看 子类 extends 父类
父类角度父类 derive(派生)了子类 5.6.2 重写父类的方法
方法的重写遵循“two same two small one large
The name of method and 形参列表相同
两小返回类型和抛出异常
一大子类的访问权限父类的访问权限
Attention:
子类覆盖父类方法后子类对象无法访问父类中被覆盖的方法。但是子类覆盖方法中可以调用父类被覆盖方法
format:
super(被覆盖方法) 如果父类方法中定义了一个private 方法子类具有一个与这个private方法相同的方法所有都相同,不是重写只是一个新方法 5.6.3 super 限定
//Using super to do the override method
public void callOverrideMethod(){
//在子类方法中通过父类被覆盖的实例方法
super.fly();
}
super 用于限定该对象调用它从父类继承得到的实例变量或方法。
super不能出现在static修饰的方法因为static修饰的方法是属于类的 如果在构造器中使用super,则super用于限定该构造器初始化的是该对象从父类继承得到的实例变量 class BaseClass{public int a 5;
}
public class SubClass extends BaseClass{public int a 7;public void accessOwner(){System.out.println(a);}public void accessBase(){System.out.println(super.a);}public static void main(String[] args){var sc new SubClass();//当系统创建了SubClass对象时实际上会为SubClass对象分配两块内存一块用于存储在SubClass对象分配两块内存一块用于存储在SubClass类中定义的a实例变量一块用于存储从BaseClass类继承得到的a实例变量sc.accessOwner();sc.accessBase();}
} 如果在某个方法中访问名为a的成员变量但没有显示指定调用者则系统查找a的顺序为 1.查找该方法中是否有名为a的局部变量
2.查找当前类中是否包含名为a的成员变量
3.查找a的直接父类中是否包含名为a的成员变量一次上溯a的所有父类直到Object class Parent{public String tag 疯狂Java讲义;
}
class Derived extends Parent{private String tag 轻量级Java EE企业应用实战;
}
public class HideTest{public static void main(String[] args){var d new Derived();System.out.println(((Parent)d).tag);}
} 5.6.4 调用父类构造器
不管是否调用super关键字子类构造器always调用父类构造器一次
子类构造器调用父类构造器分如下几种情况
1.子类构造器执行体的第一行使用super显式调用父类构造器
2.子类构造器执行体的第一行代码使用this显式调用本类中重载的构造器system将根据this调用传入的实参列表调用本类中的另一个构造器。执行本类中的另一个构造器时也会先调用父类构造器
3.子类构造器执行体中没有super和this调用会首先隐式调用父类的无参数构造器 子类构造器在初始化子类对象时父类构造器总在子类构造器之前执行。创建任何Java对象最先执行的总是java.lang.Object类的构造器 5.7 多态
Java引用变量有两个类型一个时编译类型一个是运行类型。
因为子类其实是一种特殊的父类Java允许把一个子类对象直接赋给一个父类引用变量称为向上转型。
//编译类型 对象 运行类型
BaseClass ploy new SubClass();//只能调用Subclass 的方法
BaseClass a2 new BaseClass();
//相同类型的变量、调用同一个方法时呈现出多种不同的行为特征这就是多态
//如果子类重写了父类的方法那么我们在调用这个重写的方法的时候会执行子类重写的方法而不是父类。还有一种情况调用了只有子类有的方法无法执行会报错
/*
与方法不同ploy调用父类的实例变量如果父类和子类同时具有相同的实例变量时就是父类的实例变量
*/
//使用var并不能改变变量的类型
var v2 ploy; ATTENTION
引用变量在编译阶段只能调用其编译时类型所具有的方法但运行时则执行它运行时类型所具有的方法。
Object a new Tatto();
//只能调用Object所具有的方法
//v2也会发生多态
5.7.2 引用变量的强制类型转换
如果需要让这个引用变量调用它运行时类型的方法则必须把它强制类型转换成运行时类型强制类型转换成运行时类型强制类型转化需要借助类型转化运算符。 form:
(type)variable
基本类型转换只在数值类型之间数值类型和浮点数之间不能进行转换
引用类型之间的转换只能字具有继承关系的两个类型之间进行转换如果要将一个父类实例转换为一个子类实例必须编译时类型为父类类型而运行时类型是子类类型否则会引起ClassCastException异常 为了避免出现异常可以使用instanceof 运算符来判断是否可以成功转换
if (ObjPri instanceof String){var str (String)objPri;
}
Attention:
当把子类对象赋给父类引用变量的时候被称为向上转型说明子类是特殊的父类
但把一个父类对象赋给子类引用变量的时候就需要进行强制类型转换 5.7.3 instanceof 运算符
instanceof:在进行强制类型转换之前首先判断前一个对象是否是后一个类的实例是否可以成功转换从而保证代码更加健壮。 5.8 继承与组合
继承破坏了类的封装型
父类的构造器中不要写被子类重写的类否则会变成调用被子类重写的方法 5.8.2 利用组合实现复用 class Animal{private void beat(){System.out.println(心脏跳动);}private void breathe(){System.out.prinltn(Take a breath...);}
}
class Bird{//将原本的父类组合到原来的子类作为子类的一个组合部分private Animal a;public Bird(Animal a){this.a a;}//重新定义一个自己的breath()方法public void breathe(){//直接复用a.breathe();}public void fly(){System.out.println(Flying freedom);}
}
此时的Bird对象由Animal组合而成因此在创建Bird对象之前先创建Animal对象 继承表达的是 is a的关系
组合表达的是has a的关系 5.9 初始化块 5.9.1 use it
一个类可以有多个初始化块前面定义的初始化块先执行。初始化块的语法格式如下
static{}//修饰符只能是static
没有static修饰的初始化块被称为实例初始化块
实例初始化块只在创建Java对象时隐式执行而且在构造器执行之前自动执行。
当java创建一个对象时系统先对该对象的所有实例变量分配内存前提时该类已经被加载过了-对实例变量执行初始化其初始化顺序是
先执行实例初始化块或声明实例变量时指定的初始值这两个地方指定初始值的执行顺序与它们在源代码中的排列顺序相同再执行构造器里指定的初始值 5.9.2 实例初始化块和构造器 实例初始化块是构造器的补充。
与构造器不同的时实例初始化块是一段固定执行的代码。
如果一段初始化块处理代码对所有对象完全相同且无须接收任何参数就可以把这段初始化块代码提取到初始化块中 实际上实例初始化块是一个假象用javac命令编译java类后该java类中的实例初始化块会消失——实例初始化块中代码会被插入到每个构造器代码的最前面 与构造器类似创建一个Java对象时实例代码块也会从java.lang.Object依次向下执行 如果希望类加载后对整个类进行某些初始化块操作-类初始化块-static修饰初始化块 5.9.3 类初始化块 实例初始化块负责对对象执行初始化块类初始化块则负责对类进行初始化块。 和实例初始化块相同也会追溯到java.lang.Object以上 输出结果 第六章 面向对象下
6.1 包装类
为了解决8种基本数据类型的变量不能当成Object类型变量使用的问题Java提供了包装类的概念 JDK1.5之后提供了自动装箱和自动拆箱功能。所谓自动 装箱就是可以 把一个基本类型变量直接赋给对应的 包装类变量或者赋给Object变量
自动拆箱则允许直接把包装类对象直接赋给一个对应的基本类型变量 我们来看一下java.lang.Integer类的源代码
static final Integer[] cache new Integer[-(-128)1271];
static{//执行初始化创建-128到127的Integer的实例并放入cache数组中for(int i 0;icache.length;i){cache[i] new INteger(i-128);}
}
/**
从这里咱们就可以看出java对Integer的设计就是将-128~127之间的整数自动装箱成实例并且放入数组中缓存起来实际上直接指向对应的数组元素
*/ 6.2 处理对象
//假设前面有个类
public class PrintObject{
public static void main(String[] args){
var p new Person(孙悟空);
//打印p所引用的Person对象
System.out.println(p);
}
}
运行结果
Person15db9743 explanation to the outcome:
当我们使用System.out.println()输出Person对象时实际上输出的是Person对象的toString()方法的返回值 toString()方法是Object 类里的一个实例方法所以全部的Java对象都具有toString()方法 Object类提供的toString()方法总是返回该对象实现类的”类名hashCode“值但是toString方法通常会被人作为介绍对象的方法
假如说一个对象有信息要介绍
form:
类名[field1 值1field2值2,...]public String toString(){return Apple[colorcolor,weight weight];
} 6.2.2 和equals方法 对于
如果两个变量都是基本类型且都是数值类型不要求数值类型完全相同则只要两个变量的值相同就返回true
int it 65;
System.out.println(itA);//返回true 我们来解释一下“hello” and new String(hello) 的区别
当java程序直接使用形如hello的字符串常量时JVM会使用常量池来管理这些字符串而使用new String(hello),JVM会先使用常量池来管理“hello”直接量再调用String类的构造器来创建一个新的String对象新创建的String对象将保存再堆内存中所以一共产生了两个字符串对象。 JVM常量池将保证相同的字符串直接量只有一个这样他们都将引用常量池中的同一个字符串对象 equls()方法是Object类提供的一个实例方法因此所有引用变量都可调用该方法来判断是否与其他引用变量相同其实和没什么区别
如果希望采用自定义的标准可以重写 接下来需要理解下面这段代码
class Person{private String name;private String idStr;public Person(){}public Person(String name,String idStr){this.name name;this.idStr idStr;}//忽略setter and getter ...//override the method of equeals()public boolean equals(Object obj){//如果两个对象是同一个对象if(this obj){return true;}if(obj!null obj.getClass() Person.class){var personObj (Person)obj;if(this.getIdStr().equals(personObj.getIdStr())){return true;}}return false}
} 6.3 类成员
用static修饰的类成员属于整个类不属于单个实例
6.3.1 理解类成员
在Java类中只能包含5种成员 -成员变量、方法、构造器、初始化块、内部类包括接口枚举5种成员
但通过对象来访问类变量时系统会在底层转化为通过该类来访问类变量 null对象不能访问实例成员将会引发NullPointerException异常因为null表明该实例根本不存在但是可以访问类成员 6.3.2 单例类
如果一个类始终只能创建一个实例则这个类被称为单例类。
class Singleton{//使用一个类变量来缓存曾经创建的实例private static Singleton Instance;//对构造器使用private修饰隐藏构造器private Singleton(){}//该方法可以自定义public static Singleteon getInstance(){//保证不会创建新的实例if(Instance null){Instance new Singleton();}return instance;}
} 6.4 final 修饰符
final修饰的成员变量必须有程序员显式地指定初始值
public class FinalVariableTest
{
final int a 6;//normalfinal String str;final int c;fianl static double d;// like this,在之后的构造器或者代码块中一定要赋初始值//final char ch;不赋初始值就会报错//在初始化块中可对没有指定默认值的实例变量指定初始值{str Hello;//a 9 -报错}//静态代码块可对没有赋值的类变量指定初始值static{d 5.6;}//构造器可对final实例变量(没有初始值)赋值public FinalVariableTest(){//如果在初始化块中已经对str指定初始值c 5;}public void changeFinal(){//普通方法不能对final修饰的成员变量赋值}
} 6.4.3 final修饰基本类型变量和引用类型变量的区别
基本类型变量不能别改变对于引用类型便来给你保存的仅仅是一个引用final只保证这个引用类型变量所引用的地址不会改变即一直引用同一个对象但这个对象可以改变
看下代码秒懂
class Person
{private int age;public Person(int age){this.age age;}
}
public class FinalReferenceTest{publlic static void main(String[] args){//final修饰数组变量iArr是一个引用变量final int[] iArr [5,6,12,9];System.out.println(Arrays.toString(iArr));iArr[2] 2;//legal//iArr null;//illegalfinal var p new Person(45);p.setAge(23);//p null; illegal}
}
6.4.4 可执行“宏替换”的final变量 对于一个final变量中只要满足三点就是直接量还不如直接看特例
final var a 3;
System.out.println(a);//the same as sop(3); 有一种情况不会变成宏变量就是调用了方法
final var book2 疯狂讲义String.valueOf(99);
或者是访问了普通变量
var s1 疯狂java
var str1 疯狂;
var str2 java;
var s3 str1 str2;
System,out.println(s3 s1);
s1在编译时候确定而str1 and str2 是两个普通变量编译器不会执行“宏替换”因此无法确定s3的值 6.4.5 final方法
public class FinalOverload{
//final修饰的方法只是不能被重写完全可以被重载
public final void test(){}
public final void test(String args){}
}
//演示不可变量
public class Address{//这其实就是两个不可变的量private final String detail;private final String postCode;//在构造器里初始化两个实例变量public Address(String detail,String postCode){this.detail detail;this.postCode postCode;}//创建完之后就无法修改该Address对象的实例变量的值
}
设计一个不可变类
如果需要设计一个不可变类尤其要注意其引用类型的成员变量的类是可变的如果引用类型的成员变量是可变的就必须采用必要的措施来保护该成员变量所引用的对象不会被修改
class Name
{private String firstName;private String lastName;public Name(){}public Name(String firstName,String lastName){this.firstName firstName;this.lastName lastName;}//省略firstName,lastName的getter和seetter方法
}
public class Person
{private final Name name;/*public Person(Name name){this.name name;}public Name getName(){
return name;}public static void main(String[] args){var n new Name(悟空,孙);var p new Person(n);System.out.println(p.getame().getFirstName());n.setFirstName(八戒)//这样就破坏了不可变类的性质了}
}
*///所以我们可以新定一个对象这个name对象是独属于Person类的public class Person{private final Name name;public Person(Name name){//设置name实例变量为临时创建的Name对象该对象与传入的name参数相同这样就算改变原先name的属性值也没有任何用因为指向的对象不一样this.name new Name(name.getFirstName(),name.getLastNmae());}public Name getName(){//返回一个匿名对象该对象的firstName和LastName相同return new Name(name.getFirstName(name.getLastName(),name.getLastName());}} 6.5.1 抽象方法和抽象类
有抽象方法的类只能被定义成抽象类抽象类里没有抽象方法
定义抽象方法不需要有花括号
public abstract class Shape{{System.out.println(执行Shape的初始化块...);}private String color;public abstract double calPerimerter();public Shape(){}//定义Shape的构造器该构造器不是用于创建Shape对象//只是被子类继承
}