1、JAVA笔记 JAVA中一些需要特别注意的地方 一、JAVA -SE部分:byte范围(占8位):-128127short范围(占16位):-3276832767int范围(占32位):-21474836482147483647long范围(占64位):1. 关于引用传递的问题: 所谓的引用传递,就是将一个堆内存空间的使用权给多个栈内存空间,每个栈内存空间都可以修改堆内存中的内容所有的对象名称都在栈内存中保存,而对象的具体内容 则保存在对应的堆内存中,更准确的说法就是在栈内存中实际保存的是堆内存空间的访问地址 具体内存分配如下:使用new开辟堆内存空间存储引用(实例)指向对应的堆内存 存储对象
2、Name=null;Age=0; 堆内存per栈内存Person per=new Person( ); 例如现在new一个对象:Person per1=new Person( );现在又有如下语句:Person per2=null; per2=per1;那么设置per2对象的内容实际上就是设置per1对象的内容,假如per1对象的name、age属性值分别为“张三”、23,那么通过以下语句可以修改per1对象的属性值:per2.name=李四 ; per2.age=32; 那么:Per1.name=李四 ; per1.age=32; 注意:匿名对象只在堆内存中开辟空间,而不会在栈内存中开辟空间
3、2.length和length( )的区别:使用length取得数组的长度使用length( )方法取得字符串的长度3.访问控制权限:(1)private访问权限:private属于私有访问权限,可以用在属性的定义、方法的声明 上,一旦使用了private关键字声明,则只能在本类中访问;(2)default(默认)访问权限:如果一个类中的属性或方法没有使用任何的访问权限声明, 则就是默认的访问权限,默认的访问权限可以被本包中的其 他类所访问,但是不能被其他包中的类所访问;(3)protected访问权限:protected属于受保护的访问权限,一个类中的成员如果使用了 protected访问权
4、限,则只能被本包及不同包的子类所访问;(4)public访问权限:public属于公共访问权限,如果一个类中的成员使用了public访 问权限,就可以被所有的类访问,不管是不是在同一个包中。 对以上所述列表如下:类访问修饰符序号说明1类的修饰符只有public和default两个;2public修饰类时表示任何包的其它类都可以访问该类;3访问修饰符为default时只有在同一个包里的类才能访问它,其他包里的都不行;4类的构造函数(构造器) 不能用final、abstract、synchronized、native、static等关键字进行修饰;5特殊说明:成员内部类除了可以用成4种员访问修饰符
5、外,还可以用static修饰; 局部内部类【类方法里定义的内部类】只能使用abstract或者final修饰。成员访问修饰符(public、protected、default、private)序号规则说明1java的成员访问修饰符有4种:public、private、protected、default2public static = static public; 3类的成员访问修饰符的详细描述如下:(表示允许访问,表示不能访问)visibilitypublicprotecteddefaultprivate在本类中能否访问在同一个包中不同的类中能否访问在不同包的子类中能否访问在不同的包中不同的类
6、中能否访问综合上表,访问修饰符的访问权限为:publicprotecteddefaultprivate4. 关于=和equals的区别:当使用=来判断两个变量是否相等时,如果两个变量是基本类型变量,且都是数值类型(不一定要求数据类型严格相同),则只要两个变量的值相等,就将返回true;但对于两个引用类型的变量,只要他们指向同一个对象,=判断才会返回true。例如以下程序:public class StringDemopublic static void main(String args)String str1=hello ;String str2=new String(hello);Strin
7、g str3=str2 ;String str4=ab+String.valueOf(88);System.out.println( str1=str2);System.out.println( str1=str3);System.out.println( str2=str3);System.out.println(str4=ab88);/打印falseString s1=疯狂Java;String s2=疯狂+Java;System.out.println(s1=s2);/打印trueString s3=疯狂;String s4=Java;String s5=疯狂Java;String s6
8、=s3+s4;System.out.println(s6=s5);/打印false程序的输出结果为:false false true false true false对于str1和str2来说,其内容分别保存在堆内存的不同地址空间中,所以即使内容相同,但是地址的值是不相同的,所以str1和str2比较不相等。而str2和str3指向同一堆内存空间,是同一地址,所以最终结果str2和str3的地址值是相同的。同理,str1和str3的地址也不相等,所以返回了false。至于str4,由于该变量的值需要调用String类的方法,编译时无法确定str4的值。至于s6,他的值由s3和s4进行连接运算后
9、得到,由于s3和s4只是两个普通的变量,编译器不会执行“宏替换”,编译时无法确定s6的值,也就无法让s6指向字符连接池中缓存的疯狂Java。要让s6=s5输出true也很简单,只要s3和s4都用final修饰,这样在执行对s6的拼接时就会执行对s3和s4的宏替换,这样编译器在编译阶段就可以确定s6的值,就会让s6指向缓存的疯狂Java。从上面的例子可以看出=是用来进行堆内存地址值比较的,如果要判断两个字符串的内容是否相同,则用String类提供的equals方法。如果要自定义任意两个对象是否相等,可以重写equals方法来实现,因为Object默认提供的equals方法只是比较对象的地址,即O
10、bject类的equals方法比较的结果与=运算符比较的结果完全相同。5.String两种实例化方式的区别: 第一种实例化方法:String str1=hello ; String str2=hello ; String str3=hello ; 虽然申明了3个字符串变量,但这三个字符串指向的堆内存地址 空间都是同一个,也就是说只要以后申明的字符串内容相同,则 不会再开辟新的内存空间第二种实例化方法:String str=new String(hello); 使用这种方法时,不管如何都会再开辟一个新的空间6.普通代码块、构造块、静态代码块:普通代码块:直接在方法或者语句中定义的代码块;构造块:
11、直接写在类中的代码块;静态代码块:用static关键字申明的代码块;特点:构造块优先于构造方法执行,而且每次实例化对象时都会执 行构造块中的代码; 主方法所在的类中定义的静态代码块优先于主方法执行 【注:静态代码块不能定义在主方法内】; 在类中定义的静态块会优先于构造块和构造方法的执行,而 且不管有多少个对象产生,静态代码块只执行一次。Java中静态初始化块、初始化块和构造方法的执行顺序:当该类没有父类时顺序是这样的:第一次创建对象时:静态代码块 初始化代码块 构造方法第二次创建对象时:初始化代码块 构造方法 静态代码块只执行一次当该类有父类时顺序是这样的:class Parent publi
12、c static String p_StaticField = 父类-静态变量; public String p_Field = 父类-变量; / 代码块 System.out.println(p_Field); System.out.println(父类-初始化块); / 构造函数 public Parent() System.out.println(父类-构造器); / 静态初始化块 static System.out.println(p_StaticField); System.out.println(父类-静态初始化块); public class StaticBlock extend
13、s Parent public static String s_StaticField = 子类-静态变量; public String s_Field = 子类-变量; System.out.println(s_Field); System.out.println(子类-初始化块); / 静态初始化块 static System.out.println(s_StaticField); System.out.println(子类-静态初始化块); public StaticBlock() System.out.println(子类-构造器); public static void main(S
14、tring args) System.out.println(-); new Parent(); System.out.println(-); new StaticBlock(); System.out.println(-); new StaticBlock(); 1、执行子类StaticBlock之前,由于父类中也有静态的变量,根据继承的特性,则先执行父类Parent的静态数据的初始化,然后再执行子类的静态数据的初始化;2、执行main方法中的new Parent(); 语句,进行Parent的类的实例化,因为Parent的静态数据已经实例化,并且在一个执行过程只实例化一次,所以在执行new
15、 Parenet()语句时,先执行非静态变量定义和类的非静态语句,之后再执行构造方法;3、执行main方法中的new StaticBlock(); 语句,进行子类的实例化,父类和子类的静态数据不执行,因为子类继承Parent,所以首先执行父类的非静态的变量和类语句的执行,再调用父类的同参数的构造方法,然后执行子类的实例化1.静态初始化块只在某个类第一次装入内存时才执行,因此只有第一次new Parent()才有“静态初始化块”输出,而后面却不执行输出。总结如下:(1)先静态。具体是先父静态-子静态(2)先父后子。先父的全部,然后子的全部。(3)优先级:父类 子类 。静态代码块 非静态代码块 构
16、造函数(与位置的前后无关系)先静态,可以这么理解,只要出现了某类的关键字,那么这个类的类变量或方法就要初始化,否则引用的时候就没有初始化的时机了;先父后子,可以这样理解,子类会引用父类的东西,那么必须先父后子。静态初始化块不能访问非静态成员(即非静态实例变量和非静态方法) 结果:父类-静态变量父类-静态初始化块子类-静态变量子类-静态初始化块-父类-变量父类-初始化块父类-构造器-父类-变量父类-初始化块父类-构造器子类-变量子类-初始化块子类-构造器-父类-变量父类-初始化块父类-构造器子类-变量子类-初始化块子类-构造器7.构造方法私有化的应用:package static_Test;cl
17、ass Singletprivate Singlet() /此处将构造方法进行封装private static Singlet instance=new Singlet();public static Singlet getInstance()return instance; public class hhpublic static void main(String args)Singlet s1=Singlet.getInstance( );Singlet s2=Singlet.getInstance( );Singlet s3=Singlet.getInstance( );System.o
18、ut.println(s1);System.out.println(s2);System.out.println(s3); 程序运行结果为:static_Test.Singlet17e4castatic_Test.Singlet17e4castatic_Test.Singlet17e4ca由以上例子可以看出:只要将构造方法私有化,就可以控制实例化对象的产 生,这样的设计称为单例设计模式,即无论程序怎么运行, Singlet类永远只会有一个实例化对象存在 。8.内部类:在外部访问内部类的格式: 外部类.内部类 内部类对象名=外部类实例.new 内部类(); 例如:Outer out=new Ou
19、ter(); Outer.Inner in=out.new Inner();使用static申明的内部类就变成了外部类,但是用static 申明的内部类不能访问非 static 的外部类属性和方法;在外部类方法中定义的内部类不能直接访问方法中的参数,如果方法中的参数要想被内 部类所访问,则参数前面必须加上final关键字。如果一个Java类的每个实例变量都被private修饰,并且为每个实例变量都提供了public修饰的setter和getter方法,那么这个类就是一个符合JavaBean规范的类。因此JavaBean总是一个封装良好的类不可变类:意思是创建该类的实例后,该实例的实例变量是不可
20、改变的。 如果要创建自定义的不可变类,可遵守如下规则:1.使用private和final修饰符来修饰该类的成员变量;2.提供带参数的构造器,用于根据传入参数来初始化类里的成员变量;3.仅仅为该类的成员变量提供getter方法,不要为该类提供setter方法, 因为普通方法无法修改final修饰的成员变量;4.如果有必要,重写equals()方法和hashcode()方法9. 一些规则:(1) 非静态方法可以访问静态成员,静态方法不能访问非静态成员;(2) 静态方法中不能使用this和super关键字,this()表示调用本类的构造方法,super()表示 调用父类的构造方法;(3) stati
21、c不能修饰构造方法。static不能修饰接口,但是当接口定义在类的内部时, 可以 用static 修饰;(4) 如果父类方法用final修饰,则禁止子类覆写该方法; fina1类中的方法自动全部为fina1 类型的;对于final类中的成员,可以定义其为final,也可以不是final ,子类无法直接 访问父类中使用private修饰的属性和方法,也无法覆写父类中的用private 修饰的方法;(5) final不能修饰抽象类,抽象类中的抽象方法绝不能被private修饰,因为其他类要继承 他,所以不能是私有的,否则不能被继承。而抽象类中的成员变量和带有方法体的方法 可以被private修饰。
22、static不能修饰抽象类中的抽象方法,即static和abstract不能同时 修饰某个方法; 抽象方法(前面用abstract修饰)只能定义在抽象类中,一般的方法也可 以定义在抽象类中;final修饰的成员变量必须显式地指定初始值,当final修饰类变量 时,必须在静态初始化块中指定初始值或者申明该类变量时指定初始值,而且只能在这 两个地方其中之一指定。当final修饰实例变量时,必须在非静态初始化块、申明该实 例变量或构造器中指定初始值,而且只能在这三个地方其中之一指定;不管是类变量还 是实例变量,当他们被final修饰时,是不能在普通方法中为他们赋值的;如果方法的 参数用final 修
23、饰,那么方法体中就不能对形参进行赋值;(6) 继承抽象类的类应能完成这个抽象类中定义的所有方法(即具体实现这些抽象方法), 否则这个子类仍然是个抽象类; 即使一个类中没有抽象方法也可以将该类申明为抽象 类。(7) 一个类只能继承一个父类,但却能同时实现多个接口,抽象类也可以实现多个接口。 在java中一个接口是不允许继承抽象类的,但是允许一个接口继承多个接口,例如: interface A extends B,C 【 A,B,C 都为接口 】;(8) 接口的修饰符只能用public或者abstract或者default修饰,接口中不能定义构造方法, 但抽象类中可以定义构造方法;接口不能继承类;
24、(9) 接口中的方法必须定义为public访问权限,不写默认是public的, 这是绝对不可改变 的,实现接口方法时,必须使用public修饰,因为接口里的方法都是public的,而实现 类重写父类方法时访问权限只能更大或者相等,所以实现类实现接口里的方法时只能 使用public访问权限;定义在接口中的常量具有固定的修饰符public static final(连着的), 不管是否使用public static final修饰,接口里的成员变量总是使用这三个修饰符来修饰。 申明在接口中的内部类自动为public static的,也即接口中的内部类只能是静态内部类(10) 一个类要实现一个接口,
25、就必须全部实现接口中的方法;只要接口中有一个方法没有 被类实现,那么这个类就是抽象类;(11) 一个抽象类中可以包含多个接口,一个接口中也可以包含多个抽象类;(12) 抽象类和接口不能直接用来产生对象,必须通过对象的多态性进行实例化操作;(13) 非静态成员方法被覆写后,可以通过super关键字在子类中进行调用; 静态方法是 类级的,将无法使用super关键字进行调用;(14) 在静态方法内不允许访问非静态变量,不能出现 this 和 supper,如果是static 修饰的内部类,那么内部类里面也不能出现this关键字;对static关键字而言,有一条非常重要的规则:类成员(包括方法、初始化
26、块、内部类和枚举类)不能访问实例成员(包括成员变量、方法、初始化块、内部类和枚举类)。因为用static修饰的成员是属于类的,类成员的作用域比实例成员的作用域更大,完全可能出现类成员初始化完成,但实例成员还没有初始化的情况,如果允许类成员访问实例成员将会引起大量错误;(15) 不能覆写父类的属性以及静态方法;如果子类定义了和父类同名的实例变量,则会发生子类实例变量隐藏父类实例变量的情形,在子类定义的方法中可以通过super来访问父类中被隐藏的实例变量。子类不能继承父类的构造方法;只有方法能表现出多态 性,实例变量则不具备多态性(16) 父类中的static方法不能被子类覆写(可以通过编译,但是
27、失去了多态性),但可以被继承;而父类中的属性不管用什么修饰符都不能被子类覆写,但可以被继 承;private方法和属性不能被子类继承;(17) 如果一个类实现了多个接口,而且这几个接口中有相同的方法和相同的常量,那么 相同的常量可以通过【InterfaceName.常量名】的形式来访问,相同的方法则只需要实现一次即可。(18) 如果外部类成员变量、内部类成员变量与内部类里某个方法的局部变量同名,假设这三者都是String prop,那么在内部类中访问这三者的办法依次是:OuterClass.this.prop 、this.prop、prop。局部内部类和匿名内部类都不是 类成员,要定义匿名内部
28、类的前提:内部类需要继承一个外部的类或者实现一个外部的接口,但最多只能继承一个父类或者实现一个接口;执行下面代码,只创建了外部类对象,还未创建内部类对象:Outer outer=new Outer();(19) 匿名内部类不能是抽象类。匿名内部类里面不能有构造方法【包括通过接口来创建匿 名内部类时】,因为匿名内部类没有类名,所以无法定义构造器,但匿名内部类可以 定义初始化块,可以通过实例初始化块来完成构造器需要完成的事情。匿名内部类不能定义任何静态成员、方法和类。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类;(20) 外部类的静态方法、静态代码块不能访问非静态内部类;静
29、态内部类可以包含静态成员也可以包含非静态成员。静态内部类只能访问外部类的静态成员,即使是静态内部类的非静态 方法也不能访问外部类的非静态成员。访问静态内部类中的静态方法可以这样访问:OuterClass.InnerClass.function(); 创建内部类实例的方法:Outer.Inner inner=new Outer().new Inner();在 外部类中访问静态内部类中的静态成员变量prop的办法:InnerClass.prop(21) 非静态内部类可以有子类,而且非静态内部类的子类不一定是内部类,它可以是一个外部普通的类。非静态内部类里不能有静态方法、静态成员变量、静态初始化块,但可以包含普通初始化块。如果非静态内部类中定义了静态成员变量,那么该内部类要么被static修饰,要么该静态成员变量被定义为static final;非静态内部类的成员只在非静态内部类范围内是
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1