Java学习笔记整理细节.docx
- 文档编号:11388773
- 上传时间:2023-02-28
- 格式:DOCX
- 页数:32
- 大小:33.89KB
Java学习笔记整理细节.docx
《Java学习笔记整理细节.docx》由会员分享,可在线阅读,更多相关《Java学习笔记整理细节.docx(32页珍藏版)》请在冰豆网上搜索。
Java学习笔记整理细节
Java学习笔记整理
本文档是我个人整理的,首先是想通过完成本文档更加扎实自己的基础加强对java语言的理解,然后就是想给入了门的同志们做下贡献。
当然,本文档主要是对java语言基础(当然还有很多基础没有涉及到)的进行较全面的理解已经整理,只要充分掌握了基础知识,学习高级部分的知识才会事半功倍犹如轻车熟路一般容易上手。
正文:
CLASSPATH的设置:
我们知道运行java必须要设置CLASSPATH环境变量,但是sunjava1.4之后改进了设计,JRE会自动搜索当前路径下的类文件,而且使用java的编译和运行工具时,系统会自动加载dt.jar和tools.jar文件中的类,因此不再需要设置该环境变量。
当然,如果你设置了CLASSPATH环境变量就必须设置全,比如包含当前路径,否则将会出现找不到类的问题。
Java程序的源文件必须与public类的类(接口)名相同,如果源文件所有类都没有使用public修饰,则文件名可以是任意合法的文件名,因此,一个Java源文件里最多自能定义一个public类(接口)。
运算符的结合性和优先级
只有单目运算符,赋值运算符和三目运算符是从右向左结合的,其余全是左结合的。
运算符优先级
运算符说明java运算符
分隔符.[](){},;
单目运算符++--~!
强制类型转换运算符(type)
四则运算符和求余运算
移位运算符<<>>>>>
关系运算符<<=>>=instanceof
等价运算符==!
=
按位与&
按位异或^
按位或|
条件与&&
条件或||
三目运算符?
:
赋值运算符=+=-=/=*=&=|=^\<<=>>=>>>=%=
breakcontinue后跟标签,可以直接结束其外层循环。
return用于结束整个方法。
数组
定义数组时不能指定数组的长度。
foreach
当使用foreach来迭代访问数组元素时,foreach中的循环变量相当于一个临时变量,整个临时变量并不是数组元素,它只是保存了数组元素的值(深负责),因此如果希望改变数组元素的值,则不能使用这种foreach循环。
栈内存和堆内存之分
当一个方法执行是,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将被销毁,因此,所有在方法定义的变量都是放在栈内存中的。
当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,这个运行时数据区就是堆内存。
只有当一个对象没有任何引用变量引用它时,才会在合适的时机回收它。
面向对象
this可以代表任何对象,当this出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的,它所代表对象只能是当前类;只有当这个方法被调用时,他所代表的对象才能被确定下来。
static修饰的方法中不能使用this引用,所以static修饰的方法中不能访问没有使用static修饰的普通成员。
static用来修饰方法和属性等成员。
局部成员的上已经程序单元是方法不是类,使用static修饰它们是没有意义的,所以局部成员都不能使用static修饰,
在构造器中使用this引用时,this总是引用该构造器正在初始化的对象。
方法本身是指令的操作码部分,保存在stack中,方法内部变量作为指令的操作数部分,跟着指令的操作码之后,保存在stack中(实际是简单类型保存在stack中,引用类型在stack中保存地址,在heap中保存值)。
对象实例以及非静态属性保存在heap中的,而heap必须通过stack中的地址指针才能够被指令(类的方法)访问到。
静态属性保存在stack中(这是网上找到的说,笔者认为应该是静态属性的地址保存在stack中)。
非静态方法有一个隐含的传入参数,该参数是JVM给的,和我们的代码无关,这个隐含参数就是对象实例在stack中的地址指针(this)。
因此非静态方法(在stack中的指令代码)总是可以找到自己专用数据(在heap中的对象属性值)。
当然非静态方法也必须获得该隐含参数,因此在调用非静态方法之前,必须先new一个对象实例,获得static中地址的指针,否则JVM将无法将隐含参数传给非静态方法。
而静态方法无需此隐含参数,因此不需要new对象,只要class文件被ClassLoaderload进入JVM的stack,该方法即可被调用,当然此时静态方法存取不到heap中的对象属性的。
形成长度可变的方法
publicvoidtest(inta,String…books){}
可以传入多个字符串参数作为参数值,其实是可以看着参数数组。
但一个方法只能有一个长度可变的形成且位于形参列表的最后。
方法重载
方法的重载要求:
两同(同一个类中的方法名相同),一不同(参数列表不同)(不建议使用长度可变的形参重载方法),跟方法的其他部分(返回值类型(有时我们调用方法时不需要返回值,就不能根据返回值类型来确定到底是调用哪个方法),修饰符等)没有任何关系。
系统在第一次使用类加载类,并初始化类。
类属性从这个类准备阶段起开始存在。
系统不会为局部变量执行初始化,局部变量在访问之前一定要确定是已经初始化。
模块设计追求高内聚(尽可能把模块的内部数据,功能实现细节隐藏在模块内部独立完成,不允许外部直接干预),低耦合(仅暴露少来的方法给外部使用)
构造器
如果我们提供了自定义的构造器,系统不再提供默认的构造器,通常我们都保留无参数的默认构造器。
多态性
当编译时类型和运行时类型不一致,就会出现所谓的多态。
当把子类对象赋给父类引用变量时,被称为向上转型,这个总是可以成功的,但把一个父类对象赋给一个子类引用变量时,就需要强制类型转换,而且还可能在运行时产生ClassCastException异常(当这个父类对象编译时类型为父类类型,运行时类型是子类类型才是正确的),使用instanceof运算符可以让强制类型转换更安全。
Instanceof运算符
Instanceof运算符前面操作数的编译时类型要么与后面类相同,要么是后面类的父类,否则会引起编译错误。
Instanceof运算符前面的对象是否是后面的类,或者其子类。
实现类的实例。
如果是,就返回true,否则返回false。
经过instanceof运算符判断一个对象是否可以强制类型转换,然后在使用(type)运算符进行强制转换,从而保证程序不会出现错误。
初始化块,构造器质性顺序
当Java创建一个对象时,系统先为该对象的所有实例属性分配内存(前提是该类已经被加载过了),接着程序开始对这些实例属性执行初始化,其初始化顺序是:
先执行初始化块或声明属性是指定的初始化值,然后执行构造器里指定的初始值。
类初始化阶段:
(类初始化只执行依次,然后会在虚拟机一直存在)
先执行最顶层父类的静态初始化块,依次向下,最后执行当前类的静态初始化块
对象初始化阶段:
(每次创建实例对象是都要进行)
先执行最最顶层父类的初始化块,构造器,依次向下,最后执行当前类初始化块。
构造器。
初始化块和声明指定初始化值,他们的执行顺序与源代码中的排列顺序相同。
基本类型之间的转换
XxxparseXxx(Strings)将字符串类型转换成基本类型(除了Character之外)
String中的valueOf()将基本类型转换成字符串。
==和equals
==判断两个变量是否相等是,如果2个变量是基本类型的变量,且都是数值型(不一定要求数据类型严格形同),则只要两个变量值相等,就返回true;但当判断两个引用类型的变量,必须它们指向同一个对象是,==判断才会返回true。
equals在比较字符串是只要两个字符串引用变量的指向内容相等就返回true(String类已经重写了Object的equals方法),自定义的类要想达到这样的效果,必须重写Object的equals方法(自定义标准),否则用这个方法判断两个对象相等的标准与==符号是没有区别的。
单例类(Singleton)
一个类只能创建一个实例
eg:
classSingleton
{
privatestaticSingletoninstance;
//隐藏构造器
privateSingleton(){}
//提供一个静态方法,用于返回Singleton实例
//该方法可以加入自定义的控制,保证只产生一个Singleton对象
publicstaticSingletongetInstance()
{
if(instance==null)
{
Instance=newSingleton();
}
returninstance;
}
}
这样用getInstance返回的对象始终都是同一个。
final修饰符
当final修饰引用类型变量时,final只保证这个引用所引用的地址不会改变即一直引用同一个对象,但这个对象可以发生改变。
如果final修饰的变量是基本数据类型,且在编译时就可以确定该变量的值,于是可以把该变量当成常量处理,如果是修饰引用数据类型,就无法在编译时就获得值,而必须在运行时才能得到值。
成员变量是随着类初始化或对象初始化而初始化的。
当类初始化时,系统会为该类的类属性分配内存,并分配默认值;当创建对象时,系统会为该对象的和私立属性分配内存,并分配默认值。
类属性:
可在静态初始化块中,声明该属性时指定初始值
实例属性:
可在非静态初始化块中,声明该属性、构造器中指定初始值
而且上面初始化操作要其只能被初始化一次。
(必须由程序员显示初始化)
如果在构造器,初始化块中对final成员变量进行初始化,则不要在初始化之前访问final成员变量的值,否则会出现“可能未初始化变量”的错误。
(系统不会进行隐式初始化)。
final修饰的方法只是不能被重载,并不是不能被重载。
抽象类
抽象方法不能有方法体abstractvoidStringgetName();
只要含有抽象方法(直接定义了一个抽象方法;继承了一个抽象父类,但没有完全实现父类包含的抽象方法;以及实现一个接口,但没有完全实现接口包含的抽象方法)的类就是抽象类
抽象类可以包含普通类的成分,但是必须有抽象方法。
abstract不能用于修饰属性和构造器,private和abstract不能同时使用。
更彻底的抽象:
接口
修饰符可以是public或者省略,省略了public访问控制符,则只有在相同包结构下才可以访问该接口。
一个接口可以有多个直接父接口,但不能继承类。
一个接口不能包含构造器和初始化块定义,可以包含属性(只能是常量),方法(只能是抽象方法),内部类,内部接口,和枚举类定义。
定义接口成员是,可以省略访问控制修饰符,如果指定访问修饰符,只能使用public修饰符。
在接口定义属性时,不管是否使用publicstaticfinal修饰符,接口里的属性总是使用者三个修饰符来修饰。
同样接口总是使用publicabstract来修饰。
接口不可使用static修饰接口里定义的方法。
同理接口总是使用publicstatic对内部类(静态内部类),内部接口和枚举类进行修饰。
内部类
内部类相当外部类定义的一个普通方法,可以访问外部类的私有数据和方法。
当内部类和外部类的成员或者方法出现重名时,可以使用this和外部类名.this来区分。
外部类就相当一个命名空间。
非静态内部类
非静态内部类对象必须寄存在外部类对象里,故要创建一个非静态内部类一定要有通过外部了对象。
在静态方法中不能直接通过new内部类了创建内部类对象(没有外部类对象)(类似静态方法不能调用非静态方法以及访问非静态属性)。
非静态内部类里不能有静态方法,静态属性,静态初始化块,可以有普通初始化块。
静态内部类
静态内部类相当于一个外部类的一个静态方法。
内部类的使用
Out.Inin=newOut().newIn();
当继承内部类是一定要有外部类对象来调用内部类的构造器。
局部内部类
局部内部类无需使用访问控制阀和static修饰符修饰
匿名内部类
匿名内部了不能是抽象类,不能定义构造器,因为匿名内部类没有类名,所以无法定义构造器,但可以定义实例初始化块。
枚举类(省略)
泛型
当使用泛型接口、父类时不能再包含类型形参,如继承带泛型的父类、接口要传入世界参数类型。
如publicclassAextendsB
ArrayList
instanceof运算符后不能使用泛型类。
List
如ArrayList
这点与数组不用,如果Apple是Fruit的子类,则Apple[]依然是Fruit[]的子类
类型通配符
为了表示各种List的父类,使用类型通配符“?
”,但是并不能把元素加入到其中(否则会引起编译错误),因为我们并不知道元素的类型,唯一例外的是null,它是所有引用类的实例。
其次,我们使用get()方法返回List
>集合指定索引的元素,其返回值是一个文职类型,当可以肯定的是,它是一个Object类型。
前面我们使用List
设定通配符的上限
List
ExtendsFruit>同样此处我们使用add参数类型是?
extendsFruit它表示Fruit未知的子类,我们无法准确知道这个类型是什么,所以我们无法将任何对象添加到这种集合中。
设定类型形参的上限
classA
更极端classA
泛型方法
public
{
t.add(a);
}
如果无需向泛型集合添加元素,或者修改泛型集合的元素时,可以使用类型通配符,无需使用泛型方法。
设定通配符的下限
List
superType>它表示它必须是Type本身或者Type的父类。
泛型的擦除和转换
擦除,当把一个具有泛型形象的对象赋给另一个没有泛型信息的变量时,则所有在尖括号直接的类型信息都被扔掉,如List
转换,
List
li.add(6);
//编译运行正常,只是引起“未经检查的转换”的警告
Listlist=li;//泛型擦除
List
System.out.println(ls.get(0));//将引起运行时异常
//同样会引起运行时异常
System.out.println((String)li.get(0));
泛型数组
数组元素的类型不能包含类型变量或类型形参,除非是无上限的类型通配符。
List
但可以
List
使用时候注意不要引起“ClassCastException”异常。
异常处理
进行异常捕获的时候一定要先捕获小的异常,然后在捕获大的异常。
在finally块中使用了return或throw的语句,将会导致try块、catch块中的return,throw语句失效。
当java程序执行try块、catch块时遇到returnthrow语句(没有System.exit
(1);语句),这个两个语句或导致该方法立即结束,所以系统并不会立即执行这个两个语句,而是去寻找该异常处理流程中是否包含finally块,如果有finally块,只有当finally块执行完毕,系统才会再次跳回来执行try块、catch块里的return或throw语句。
数组与内存控制
数组静态初始化:
String[]books=newString[]{“woshi“,”zhongshan”,”daxue”};
String[]books={“woshi“,”zhongshan”,”daxue”};
数组动态初始化:
String[]books=newString[5];
执行动态初始化时系统将为数组元素分配默认初始值。
不要同时使用静态初始化和动态初始化。
通过其他数组赋值初始化:
String[]books1=books;
数组变量是一种引用类型的变量(存储的是数组的引用),数组变量本身存储在栈区,指向的内容是指向堆区。
在Java中对象的引用本身不需要进行初始化,而对象本身才需要进行初始化。
所有局部变量都是放在各自的方法栈内存里保存的,但引用类型变量所引用的对象则总是存储在堆内存中的。
只要程序通过引用类型变量访问属性或者调用方法,则该引用类型将被其所引用的对象代替,即要进行初始化。
int[]sArra=null;
System.out.println(sArra)//这是没有问题的,输出的是null
对象与内存控制
实例变量和类变量
static不能修饰外部类,局部变量,局部内部类
//下面代码将提示:
非法向前引用
intnum1=num2+1;
intnum2=3;
上面代码变量同时用static修饰同样会出现上述问题。
但
//下面代码正常
intnum1=num2+1;
staticintnum2=3;
这说明类变量的初始化时间总是比实例变量之前。
使用javap–c类名可以得到该类初始化的过程,当我们队一个类初始化过程不是很清楚的时候不妨尝试下该命令。
实例变量的初始化时机
每次创建Java对象的时都会为实例变量分配内存空间,并对实例变量执行初始化
实例变量初始化有三种方式
定义实例变量时指定初始值;
非静态初始化块中对实例变量指定初始值;
构造器中对实例变量指定初始值
其实前两种初始化执行顺序和它们在源代码中位置排列相同,也就拥有想多等级初始化时机,但都比第三种初始化方式更早。
实际中实例变量初始化指定初始值和初始化块当经过编译器处理后,它们都会被提取到构造器中。
例如:
doublea=24;
实际上会被分成如下2步执行:
(1)doublea;创建Java对象时系统根据该语句为该对象分配内存
(2)a=24;这条语句是被提取到Java类的构造器中执行
publicclassJavapToolTest
{
//初始化快中为count实例变量指定初始值
count=12;
}
intcount=20;
//定义两个构造器
publicJavapToolTest()
{
System.out.println(count);
}
使用javap–c命令可以得到如下代码:
结果就一目了然了
C:
\Users\D.S.Qiu\Desktop\codes\codes\02\2.1>javap-cJavapToolTest
Compiledfrom"JavapToolTest.java"
publicclassJavapToolTest{
intcount;
publicJavapToolTest();
Code:
0:
aload_0
1:
invokespecial#1//Methodjava/lang/Object."
()V
4:
aload_0
5:
bipush12
7:
putfield#2//Fieldcount:
I
10:
aload_0
11:
bipush20
13:
putfield#2//Fieldcount:
I
16:
getstatic#3//Fieldjava/lang/System.out:
Ljava/
io/PrintStream;
19:
aload_0
20:
getfield#2//Fieldcount:
I
23:
invokevirtual#4//Methodjava/io/PrintStream.printl
n:
(I)V
26:
return
类变量初始化时机
类变量初始化的方法
定义类变量时指定初始值;
静态初始化块中对类变量指定初始值
初始化时机与实力变量初始化时机类似。
对没有给出初始化的变量系统总分配默认值。
父类构造器
当创建Java对象时,程序总会先依次调用每个父类的非静态初始化块,父类构造器执行初始化,最后才调用本类的非静态初始块,构造器执行初始化。
隐式调用和显示调用
如果子类构造器中没有使用super调用父类构造器,将会隐式调用父类无参数的构造器。
super和this调用构造器最多只能使用其中一者,而且必须作为构造器代码的第一行。
访问子类对象的实例变量
下面看一个极端的例子
classBase
{
//定义了一个名为i的实例变量
privateinti=2;
publicBase()
{
this.display();
}
publicvoiddisplay()
{
System.out.println(i);
}
}
//继承Base的Derived子类
classDerivedextendsBase
{
//定义了一个名为i的实例变量
privateinti=22;
//构造器,将实例变量i初始化为222
publicDerived()
{
i=222;
}
publicvoiddisplay()
{
System.out.println(i);
}
}
publicclassTest
{
publi
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Java 学习 笔记 整理 细节