JAVA笔记.docx
《JAVA笔记.docx》由会员分享,可在线阅读,更多相关《JAVA笔记.docx(41页珍藏版)》请在冰豆网上搜索。
JAVA笔记
JAVA中一些需要特别注意的地方
一、JAVA-SE部分:
byte范围(占8位):
-128~127
short范围(占16位):
-32768~32767
int范围(占32位):
-2147483648~2147483647
long范围(占64位):
1.关于引用传递的问题:
所谓的引用传递,就是将一个堆内存空间的使用权给多个栈内存空间,每个栈内存空间都可以修改堆内存中的内容
所有的对象名称都在栈内存中保存,而对象的具体内容则保存在对应的堆内存中,更准确的说法就是在栈内存中实际保存的是堆内存空间的访问地址
具体内存分配如下:
使用new开辟堆内存空间
存储引用(实例)
指向对应的堆内存
存储对象
Name=null;
Age=0;
堆内存
per
栈内存
Personper=newPerson();
例如现在new一个对象:
Personper1=newPerson();
现在又有如下语句:
Personper2=null;per2=per1;
那么设置per2对象的内容实际上就是设置per1对象的内容,假如per1对象的name、age属性值分别为“张三”、23,那么通过以下语句可以修改per1对象的属性值:
per2.name="李四";per2.age=32;那么:
Per1.name="李四";per1.age=32;
注意:
匿名对象只在堆内存中开辟空间,而不会在栈内存中开辟空间
2.length和length()的区别:
使用length取得数组的长度
使用length()方法取得字符串的长度
3.访问控制权限:
(1)private访问权限:
private属于私有访问权限,可以用在属性的定义、方法的声明
上,一旦使用了private关键字声明,则只能在本类中访问;
(2)default(默认)访问权限:
如果一个类中的属性或方法没有使用任何的访问权限声明,
则就是默认的访问权限,默认的访问权限可以被本包中的其
他类所访问,但是不能被其他包中的类所访问;
(3)protected访问权限:
protected属于受保护的访问权限,一个类中的成员如果使用了
protected访问权限,则只能被本包及不同包的子类所访问;
(4)public访问权限:
public属于公共访问权限,如果一个类中的成员使用了public访
问权限,就可以被所有的类访问,不管是不是在同一个包中。
对以上所述列表如下:
类访问修饰符
序号
说明
1
类的修饰符只有public和default两个;
2
public修饰类时表示任何包的其它类都可以访问该类;
3
访问修饰符为default时只有在同一个包里的类才能访问它,其他包里的都不行;
4
类的构造函数(构造器)不能用final、abstract、synchronized、native、static等关键字进行修饰;
5
特殊说明:
成员内部类除了可以用成4种员访问修饰符外,还可以用static修饰;
局部内部类【类方法里定义的内部类】只能使用abstract或者final修饰。
成员访问修饰符(public、protected、default、private)
序号
规则说明
1
java的成员访问修饰符有4种:
public、private、protected、default
2
publicstatic==staticpublic;
3
类的成员访问修饰符的详细描述如下:
(√表示允许访问,×表示不能访问)
visibility
public
protected
default
private
在本类中能否访问
√
√
√
√
在同一个包中不同的类中能否访问
√
√
√
×
在不同包的子类中能否访问
√
√
×
×
在不同的包中不同的类中能否访问
√
×
×
×
综合上表,访问修饰符的访问权限为:
public>protected>default>private
4.关于==和equals的区别:
当使用==来判断两个变量是否相等时,如果两个变量是基本类型变量,且都是数值类型(不一定要求数据类型严格相同),则只要两个变量的值相等,就将返回true;但对于两个引用类型的变量,只要他们指向同一个对象,==判断才会返回true。
例如以下程序:
publicclassStringDemo{
publicstaticvoidmain(String[]args){
Stringstr1="hello";
Stringstr2=newString("hello");
Stringstr3=str2;
Stringstr4="ab"+String.valueOf(88);
System.out.println(str1==str2);
System.out.println(str1==str3);
System.out.println(str2==str3);
System.out.println(str4=="ab88");//打印false
Strings1="疯狂Java";
Strings2="疯狂"+"Java";
System.out.println(s1==s2);//打印true
Strings3="疯狂";
Strings4="Java";
Strings5="疯狂Java";
Strings6=s3+s4;
System.out.println(s6==s5);//打印false
}
}
程序的输出结果为:
falsefalsetruefalsetruefalse
对于str1和str2来说,其内容分别保存在堆内存的不同地址空间中,所以即使内容相同,但是地址的值是不相同的,所以str1和str2比较不相等。
而str2和str3指向同一堆内存空间,是同一地址,所以最终结果str2和str3的地址值是相同的。
同理,str1和str3的地址也不相等,所以返回了false。
至于str4,由于该变量的值需要调用String类的方法,编译时无法确定str4的值。
至于s6,他的值由s3和s4进行连接运算后得到,由于s3和s4只是两个普通的变量,编译器不会执行“宏替换”,编译时无法确定s6的值,也就无法让s6指向字符连接池中缓存的"疯狂Java"。
要让s6==s5输出true也很简单,只要s3和s4都用final修饰,这样在执行对s6的拼接时就会执行对s3和s4的宏替换,这样编译器在编译阶段就可以确定s6的值,就会让s6指向缓存的"疯狂Java"。
从上面的例子可以看出==是用来进行堆内存地址值比较的,如果要判断两个字符串的内容是否相同,则用String类提供的equals方法。
如果要自定义任意两个对象是否相等,可以重写equals方法来实现,因为Object默认提供的equals方法只是比较对象的地址,即Object类的equals方法比较的结果与==运算符比较的结果完全相同。
5.String两种实例化方式的区别:
第一种实例化方法:
Stringstr1="hello";
Stringstr2="hello";Stringstr3="hello";
虽然申明了3个字符串变量,但这三个字符串指向的堆内存地址
空间都是同一个,也就是说只要以后申明的字符串内容相同,则
不会再开辟新的内存空间
第二种实例化方法:
Stringstr=newString("hello");
使用这种方法时,不管如何都会再开辟一个新的空间
6.普通代码块、构造块、静态代码块:
普通代码块:
直接在方法或者语句中定义的代码块;
构造块:
直接写在类中的代码块;
静态代码块:
用static关键字申明的代码块;
特点:
构造块优先于构造方法执行,而且每次实例化对象时都会执
行构造块中的代码;
主方法所在的类中定义的静态代码块优先于主方法执行
【注:
静态代码块不能定义在主方法内】;
在类中定义的静态块会优先于构造块和构造方法的执行,而
且不管有多少个对象产生,静态代码块只执行一次。
Java中静态初始化块、初始化块和构造方法的执行顺序:
当该类没有父类时顺序是这样的:
第一次创建对象时:
静态代码块> 初始化代码块 >构造方法
第二次创建对象时:
初始化代码块 >构造方法静态代码块只执行一次
当该类有父类时顺序是这样的:
classParent{
publicstaticStringp_StaticField="父类--静态变量";
publicStringp_Field="父类--变量";
//代码块
{
System.out.println(p_Field);
System.out.println("父类--初始化块");
}
//构造函数
publicParent(){
System.out.println("父类--构造器");
}
//静态初始化块
static{
System.out.println(p_StaticField);
System.out.println("父类--静态初始化块");
}
}
publicclassStaticBlockextendsParent{
publicstaticStrings_StaticField="子类--静态变量";
publicStrings_Field="子类--变量";
{
System.out.println(s_Field);
System.out.println("子类--初始化块");
}
//静态初始化块
static{
System.out.println(s_StaticField);
System.out.println("子类--静态初始化块");
}
publicStaticBlock(){
System.out.println("子类--构造器");
}
publicstaticvoidmain(String[]args){
System.out.println("-------------------");
newParent();
System.out.println("-------------------");
newStaticBlock();
System.out.println("-------------------");
newStaticBlock();
1、执行子类StaticBlock之前,由于父类中也有静态的变量,根据继承的特性,则先执行父类Parent的静态数据的初始化,然后再执行子类的静态数据的初始化;
2、执行main方法中的newParent();语句,进行Parent的类的实例化,因为Parent的静态数据已经实例化,并且在一个执行过程只实例化一次,所以在执行newParenet()语句时,先执行非静态变量定义和类的非静态语句,之后再执行构造方法;
3、执行main方法中的newStaticBlock();语句,进行子类的实例化,父类和子类的静态数据不执行,因为子类继承Parent,所以首先执行父类的非静态的变量和类语句的执行,再调用父类的同参数的构造方法,然后执行子类的实例化
1.静态初始化块只在某个类第一次装入内存时才执行,因此只有第一次newParent()才有“静态初始化块”输出,而后面却不执行输出。
总结如下:
(1)先静态。
具体是先父静态->子静态
(2)先父后子。
先父的全部,然后子的全部。
(3)优先级:
父类>子类。
静态代码块>非静态代码块>构造函数 (与位置的前后无关系)
先静态,可以这么理解,只要出现了某类的关键字,那么这个类的类变量或方法就要初始化,否则引用的时候就没有初始化的时机了;
先父后子,可以这样理解,子类会引用父类的东西,那么必须先父后子。
静态初始化块不能访问非静态成员(即非静态实例变量和非静态方法)
}
}
结果:
父类--静态变量
父类--静态初始化块
子类--静态变量
子类--静态初始化块
-------------------
父类--变量
父类--初始化块
父类--构造器
-------------------
父类--变量
父类--初始化块
父类--构造器
子类--变量
子类--初始化块
子类--构造器
-------------------
父类--变量
父类--初始化块
父类--构造器
子类--变量
子类--初始化块
子类--构造器
7.构造方法私有化的应用:
packagestatic_Test;
classSinglet{
privateSinglet(){}//此处将构造方法进行封装
privatestaticSingletinstance=newSinglet();
publicstaticSingletgetInstance()
{
returninstance;
}
}
publicclasshh{
publicstaticvoidmain(Stringargs[]){
Singlets1=Singlet.getInstance();
Singlets2=Singlet.getInstance();
Singlets3=Singlet.getInstance();
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
}}
程序运行结果为:
static_Test.Singlet@17e4ca
static_Test.Singlet@17e4ca
static_Test.Singlet@17e4ca
由以上例子可以看出:
只要将构造方法私有化,就可以控制实例化对象的产生,这样的设计称为单例设计模式,即无论程序怎么运行,Singlet类永远只会有一个实例化对象存在。
8.内部类:
在外部访问内部类的格式:
外部类.内部类内部类对象名=外部类实例.new内部类();
例如:
Outerout=newOuter();
Outer.Innerin=out.newInner();
使用static申明的内部类就变成了外部类,但是用static申明的内部类不能访问非
static的外部类属性和方法;
在外部类方法中定义的内部类不能直接访问方法中的参数,如果方法中的参数要想被内部类所访问,则参数前面必须加上final关键字。
如果一个Java类的每个实例变量都被private修饰,并且为每个实例变量都提供了public修饰的setter和getter方法,那么这个类就是一个符合JavaBean规范的类。
因此JavaBean总是一个封装良好的类
不可变类:
意思是创建该类的实例后,该实例的实例变量是不可改变的。
如果要创建自定义的不可变类,可遵守如下规则:
1.使用private和final修饰符来修饰该类的成员变量;
2.提供带参数的构造器,用于根据传入参数来初始化类里的成员变量;
3.仅仅为该类的成员变量提供getter方法,不要为该类提供setter方法,
因为普通方法无法修改final修饰的成员变量;
4.如果有必要,重写equals()方法和hashcode()方法
9.一些规则:
(1)非静态方法可以访问静态成员,静态方法不能访问非静态成员;
(2)静态方法中不能使用this和super关键字,this()表示调用本类的构造方法,super()表示
调用父类的构造方法;
(3)static不能修饰构造方法。
static不能修饰接口,但是当接口定义在类的内部时,可以
用static修饰;
(4)如果父类方法用final修饰,则禁止子类覆写该方法;fina1类中的方法自动全部为fina1
类型的;对于final类中的成员,可以定义其为final,也可以不是final,子类无法直接
访问父类中使用private修饰的属性和方法,也无法覆写父类中的用private修饰的方法;
(5)final不能修饰抽象类,抽象类中的抽象方法绝不能被private修饰,因为其他类要继承
他,所以不能是私有的,否则不能被继承。
而抽象类中的成员变量和带有方法体的方法
可以被private修饰。
static不能修饰抽象类中的抽象方法,即static和abstract不能同时
修饰某个方法;抽象方法(前面用abstract修饰)只能定义在抽象类中,一般的方法也可
以定义在抽象类中;final修饰的成员变量必须显式地指定初始值,当final修饰类变量
时,必须在静态初始化块中指定初始值或者申明该类变量时指定初始值,而且只能在这
两个地方其中之一指定。
当final修饰实例变量时,必须在非静态初始化块、申明该实
例变量或构造器中指定初始值,而且只能在这三个地方其中之一指定;不管是类变量还
是实例变量,当他们被final修饰时,是不能在普通方法中为他们赋值的;如果方法的
参数用final修饰,那么方法体中就不能对形参进行赋值;
(6)继承抽象类的类应能完成这个抽象类中定义的所有方法(即具体实现这些抽象方法),
否则这个子类仍然是个抽象类;即使一个类中没有抽象方法也可以将该类申明为抽象
类。
(7)一个类只能继承一个父类,但却能同时实现多个接口,抽象类也可以实现多个接口。
在java中一个接口是不允许继承抽象类的,但是允许一个接口继承多个接口,例如:
interfaceAextendsB,C【A,B,C都为接口】;
(8)接口的修饰符只能用public或者abstract或者default修饰,接口中不能定义构造方法,
但抽象类中可以定义构造方法;接口不能继承类;
(9)接口中的方法必须定义为public访问权限,不写默认是public的,这是绝对不可改变
的,实现接口方法时,必须使用public修饰,因为接口里的方法都是public的,而实现
类重写父类方法时访问权限只能更大或者相等,所以实现类实现接口里的方法时只能
使用public访问权限;定义在接口中的常量具有固定的修饰符publicstaticfinal(连着的),
不管是否使用publicstaticfinal修饰,接口里的成员变量总是使用这三个修饰符来修饰。
申明在接口中的内部类自动为publicstatic的,也即接口中的内部类只能是静态内部类
(10)一个类要实现一个接口,就必须全部实现接口中的方法;只要接口中有一个方法没有
被类实现,那么这个类就是抽象类;
(11)一个抽象类中可以包含多个接口,一个接口中也可以包含多个抽象类;
(12)抽象类和接口不能直接用来产生对象,必须通过对象的多态性进行实例化操作;
(13)非静态成员方法被覆写后,可以通过super关键字在子类中进行调用;静态方法是
类级的,将无法使用super关键字进行调用;
(14)在静态方法内不允许访问非静态变量,不能出现this和supper,如果是static
修饰的内部类,那么内部类里面也不能出现this关键字;对static关键字而言,有一
条非常重要的规则:
类成员(包括方法、初始化块、内部类和枚举类)不能访问实例
成员(包括成员变量、方法、初始化块、内部类和枚举类)。
因为用static修饰的成
员是属于类的,类成员的作用域比实例成员的作用域更大,完全可能出现类成员初始
化完成,但实例成员还没有初始化的情况,如果允许类成员访问实例成员将会引起大
量错误;
(15)不能覆写父类的属性以及静态方法;如果子类定义了和父类同名的实例变量,则会发
生子类实例变量隐藏父类实例变量的情形,在子类定义的方法中可以通过super来访
问父类中被隐藏的实例变量。
子类不能继承父类的构造方法;只有方法能表现出多态
性,实例变量则不具备多态性
(16)父类中的static方法不能被子类覆写(可以通过编译,但是失去了多态性),但可
以被继承;而父类中的属性不管用什么修饰符都不能被子类覆写,但可以被继
承;private方法和属性不能被子类继承;
(17)如果一个类实现了多个接口,而且这几个接口中有相同的方法和相同的常量,那么
相同的常量可以通过【InterfaceName.常量名】的形式来访问,相同的方法则只需要实
现一次即可。
(18)如果外部类成员变量、内部类成员变量与内部类里某个方法的局部变量同名,假设这
三者都是Stringprop,那么在内部类中访问这三者的办法依次是:
OuterClass.this.prop、this.prop、prop。
局部内部类和匿名内部类都不是
类成员,要定义匿名内部类的前提:
内部类需要继承一个外部的类或者实现一个外部
的接口,但最多只能继承一个父类或者实现一个接口;执行下面代码,只创建了外部
类对象,还未创建内部类对象:
Outerouter=newOuter();
(19)匿名内部类不能是抽象类。
匿名内部类里面不能有构造方法【包括通过接口来创建匿
名内部类时】,因为匿名内部类没有类名,所以无法定义构造器,但匿名内部类可以
定义初始化块,可以通过实例初始化块来完成构造器需要完成的事情。
匿名内部类不
能定义任何静态成员、方法和类。
一个匿名内部类一定是在new的后面,用其隐含实
现一个接口或实现一个类;
(20)外部类的静态方法、静态代码块不能访问非静态内部类;
静态内部类可以包含静态成员也可以包含非静态成员。
静态内部类只能访问外部类的
静态成员,即使是静态内部类的非静态方法也不能访问外部类的非静态成员。
访问
静态内部类中的静态方法可以这样访问:
OuterClass.InnerClass.function();
创建内部类实例的方法:
Outer.Innerinner=newOuter().newInner();在
外部类中访问静态内部类中的静态成员变量prop的办法:
InnerClass.prop
(21)非静态内部类可以有子类,而且非静态内部类的子类不一定是内部类,它可以是一个
外部普通的类。
非静态内部类里不能有静态方法、静态成员变量、静态初始化块,但
可以包含普通初始化块。
如果非静态内部类中定义了静态成员变量,那么该内部类要
么被static修饰,要么该静态成员变量被定义为staticfinal;非静态内部类的成员只
在非静态内部类范围内是