======================================================================
Java 第6天: Java高级特性
修饰符;接口,内部类,对象,包装类,集合,异常处理,反射.
======================================================================
(1)修饰符。
private,default,protected,public //不能修饰局部变量
private,default,protected,public: 都能修饰属性和方法,
但是只有default,public能修饰类.
Java 第6天: Java高级特性
修饰符;接口,内部类,对象,包装类,集合,异常处理,反射.
======================================================================
(1)修饰符。
private,default,protected,public //不能修饰局部变量
private,default,protected,public: 都能修饰属性和方法,
但是只有default,public能修饰类.
表1:类,方法,成员变量和局部变量的可用修饰符
修饰符
|
类
|
成员方法
|
构造方法
|
成员变量
|
局部变量
|
abstract
|
√
|
√
|
-
|
-
|
-
|
static
|
-
|
√
|
-
|
√
|
-
|
public
|
√
|
√
|
√
|
√
|
-
|
protected
|
-
|
√
|
√
|
√
|
-
|
private
|
-
|
√
|
√
|
-
|
-
|
synchronized
|
-
|
√
|
-
|
-
|
-
|
native
|
-
|
√
|
-
|
-
|
-
|
transient(暂时的)
|
-
|
-
|
-
|
√
|
-
|
volatile(易失的)
|
-
|
-
|
-
|
√
|
-
|
final
|
√
|
√
|
-
|
√
|
√
|
表2 : 访问的级别和可访问范围
访问级别
|
访问控制修饰参数
|
同类
|
同包
|
子类
|
不同的包
|
公开
|
Public
|
√
|
√
|
√
|
√
|
受保护
|
Protected
|
√
|
√
|
√
|
-
|
默认
|
Default(没有修饰)
|
√
|
√
|
-
|
-
|
私有
|
private
|
√
|
-
|
-
|
-
|
(2) static //静态的.
能修饰属性,方法,初始代码块.
package test;
publicclass TestStatic {
publicstaticvoid main(String[] args){
MyClass mc1=new MyClass();
MyClass mc2=new MyClass();
mc1.a=10;
System.out.print("mc1.a="+mc1.a);
System.out.print("mc2.a="+mc2.a);
mc2.a=20;
System.out.print("mc1.a="+mc1.a);
System.out.print("mc2.a="+mc2.a);
System.out.print("MyClass.a="+MyClass.a); // 因为a是类变量,所以可以用类名调用.
System.out.println(); // out是System里的公有的属性.
MyClass.m1(); // 类名调用.
}
}
class MyClass{
staticinta=1; // 此时叫类变量,全类公有.因此可以用类名调用.
intb=2; // 创建对象的时候才分配空间,初始化.
publicstaticvoid m1(){
System.out.println(a);
System.out.println(b);//静态方法不能访问非静态属性。
}
publicstaticvoid m2(){ // 相当于全类的,因此能用类名调用.是打破面向对象思想的.
System.out.println(a);
System.out.println(b);// 编译错误,静态方法不能访问非静态属性.因为,
}
}
属性: 类变量(static),实例变量.
局部变量不是属性.
(4)静态方法是否能覆盖?
静态方法可以覆盖,但是必需是静态方法覆盖静态方法,非静态方法不能覆盖静态方法.(此时就没有了多态.)
package test;
局部变量不是属性.
(4)静态方法是否能覆盖?
静态方法可以覆盖,但是必需是静态方法覆盖静态方法,非静态方法不能覆盖静态方法.(此时就没有了多态.)
package test;
class TestOverride{
publicstaticvoid main(String[] args){
Super s=new Sub();//只有非静态方法的覆盖才有多态.
System.out.println(s.a); // =10
}
}
class Super{
staticinta=10;
}
class Sub extends Super{
staticinta=20;
}
(5) 静态属性是在什么时候,被初始化的???
答: 在类加载的时候被初始化的.
(7) 什么叫类加载??
答: 类加载一次,然后就创建静态变量.(也就是只创建一次).如果创建对象就不用再次的加载类,在然后就创建对象.一个类在编译之后会形成.class文件,存储了类的全部消息.当JVM第一次需要用到这个类的时候,会根据ClassPath找到这个.class文件,用输入流把文件中的消息读入JVM并保存起来,这样,JVM就"认识"了这个类.
类加载时机: 第一次用这个类的时候.
1. 第一次创建类的对象,会加载
2. 访问类的静态成员,会加载.
3. 声明类的引用,不会加载.
4. 加载子类,必然先加载父类
5. 如果调用的是子类从父类中继承到静态方法,只会加载父类.
6. 如果访问的是类的静态常量,如果在编译的时候能确定这个常量的值,则运行时不会加载,否则,编译是无法确定常量的值,那么运行是就会加载.
(8) 主方法为什么是静态方法?
答: 如果不是静态的.必需先创建类对象,但是此时创建对象的方法是main方法里面,这样会造成矛盾.也就是不能创建对象.要解决这个问题就要把main方法写成静态的,要让main方法在创建对象之前调用(因为静态方法和属性是在类加载的时候就调用的,因此可以解决这个问题,呵呵)
(9)static 的第三种用法.(温馨提示:static 的前三种用法是:1.修饰属性,2.方法,3.初始化代码块)
//此时而初始化代码块只能用static 修饰,嘻嘻记住吧!!!
在第三步:调用初始代码块:在构造方法前面运行,在初始化属性的时候运行。
在前面加static 静态初始代码快.在类加载的时候运行,创建对象的时候不运行这个代码块.//太有用了!!呵呵.
重要用处: 监控虚拟机的类加载.
1. 创建对象的时候会出现.
2. 第一次访问静态方法,属性.
3. 声明一个类的一个引用,不会加载类. 虚拟机有延迟加载的功能,(能不加载就不加载,也就是编译器能确定的事情[也就是不变的量,final修饰],就不会加载类,这样会浪费内存)
4. 加载子类的时候会加载父类么????
答: 不单要加载父类而且会先加载父类.
例子: 看老师的代码: TestClassLoad.java
5.如果你调用从父类继承到的静态方法,只加载父类不加载子类.
例子:例子: 看老师的代码: TestClassLoad.java
如果覆盖了父类的静态方法,就还要加载子类.
这5个特性都在下面的代码中:
package test;
(5) 静态属性是在什么时候,被初始化的???
答: 在类加载的时候被初始化的.
(7) 什么叫类加载??
答: 类加载一次,然后就创建静态变量.(也就是只创建一次).如果创建对象就不用再次的加载类,在然后就创建对象.一个类在编译之后会形成.class文件,存储了类的全部消息.当JVM第一次需要用到这个类的时候,会根据ClassPath找到这个.class文件,用输入流把文件中的消息读入JVM并保存起来,这样,JVM就"认识"了这个类.
类加载时机: 第一次用这个类的时候.
1. 第一次创建类的对象,会加载
2. 访问类的静态成员,会加载.
3. 声明类的引用,不会加载.
4. 加载子类,必然先加载父类
5. 如果调用的是子类从父类中继承到静态方法,只会加载父类.
6. 如果访问的是类的静态常量,如果在编译的时候能确定这个常量的值,则运行时不会加载,否则,编译是无法确定常量的值,那么运行是就会加载.
(8) 主方法为什么是静态方法?
答: 如果不是静态的.必需先创建类对象,但是此时创建对象的方法是main方法里面,这样会造成矛盾.也就是不能创建对象.要解决这个问题就要把main方法写成静态的,要让main方法在创建对象之前调用(因为静态方法和属性是在类加载的时候就调用的,因此可以解决这个问题,呵呵)
(9)static 的第三种用法.(温馨提示:static 的前三种用法是:1.修饰属性,2.方法,3.初始化代码块)
//此时而初始化代码块只能用static 修饰,嘻嘻记住吧!!!
在第三步:调用初始代码块:在构造方法前面运行,在初始化属性的时候运行。
在前面加static 静态初始代码快.在类加载的时候运行,创建对象的时候不运行这个代码块.//太有用了!!呵呵.
重要用处: 监控虚拟机的类加载.
1. 创建对象的时候会出现.
2. 第一次访问静态方法,属性.
3. 声明一个类的一个引用,不会加载类. 虚拟机有延迟加载的功能,(能不加载就不加载,也就是编译器能确定的事情[也就是不变的量,final修饰],就不会加载类,这样会浪费内存)
4. 加载子类的时候会加载父类么????
答: 不单要加载父类而且会先加载父类.
例子: 看老师的代码: TestClassLoad.java
5.如果你调用从父类继承到的静态方法,只加载父类不加载子类.
例子:例子: 看老师的代码: TestClassLoad.java
如果覆盖了父类的静态方法,就还要加载子类.
这5个特性都在下面的代码中:
package test;
publicclass TestClassLoad{
publicstaticvoid main(String[] args){
// Student s=new Student();
// Student.m();
// Student s=null;
// Sub s=new Sub();
// Sub.m();
// System.out.println(ClassA.A);//这个就不会调入虚拟机.(编译器当时就确定了这个数,因此就没有必要加载这个类,会省下内存空间,呵呵)
System.out.println(ClassA.B);//此时会加载类.因为Math.random();的值不确定,要进入类才能知道.
}
}
class Student{
static{ //修饰的初始化代码块.[温馨提示: 此时只能用static 修饰,不能用private,protect,public 修饰,嘻嘻]
System.out.println("Load Student");
}
staticinta;
publicstaticvoid m(){}
public Student(){}
}
class Super{ //验证[加载子类的时候会加载父类么]
static{
System.out.println("Load Super");
}
publicstaticvoid m(){}
}
class Sub extends Super{
static{
System.out.println("Load Sub");
}
}
class ClassA{ //验证编译器确定了变量的值,就不会加载类
static{
System.out.println("Load ClassA");
}
publicstaticfinalintA=2*5; //确定不会变的量.
publicstaticfinaldoubleB=Math.random(); //只有调入这个类才能确定的量.
}
(10) 和静态有关的模式模式: GOF green of four; 23种模式
1.单例模式: (yi) 一个类只允许他有一个对象.怎么实现??
就要用到单例模式.
具体例子: 这样一个类才只能有一个对象. 实现了这个需求.呵呵.
package test;
(10) 和静态有关的模式模式: GOF green of four; 23种模式
1.单例模式: (yi) 一个类只允许他有一个对象.怎么实现??
就要用到单例模式.
具体例子: 这样一个类才只能有一个对象. 实现了这个需求.呵呵.
package test;
publicclass TestClassLoad{
publicstaticvoid main(String[] args){
LaoGong lg1=LaoGong.newInstance();
LaoGong lg2=LaoGong.newInstance();
LaoGong lg3=new LaoGong();// 这个会出现编译错误,把无参的构造方法变成私有。
LaoGong lg4=LaoGong.newInstance();// 只有这样才能编译通过.
System.out.println("");
}
}
class LaoGong{
privatestaticLaoGonglg=new LaoGong(); // 单例模式;
publicstatic LaoGong newInstance(){//返回申请的同一个对象。lg;
returnlg;
}
private LaoGong(){}// 把LaoGong lg=new LaoGong()路给堵上.
}
虚拟机机制: 一般来说一个类只加载一次.
java 起动一个虚拟机.
(11) 如果设计一个方法,不需要对象.就用static 修饰.一般用于JDK的工具类的。
(12) final 修饰变量.3个变量都能修饰 ,还能修饰类.
//对于类常量,初始化或者静态初始化代码块中可以赋值.
虚拟机机制: 一般来说一个类只加载一次.
java 起动一个虚拟机.
(11) 如果设计一个方法,不需要对象.就用static 修饰.一般用于JDK的工具类的。
(12) final 修饰变量.3个变量都能修饰 ,还能修饰类.
//对于类常量,初始化或者静态初始化代码块中可以赋值.
1. final 修饰变量
这个变量就变成了常量(一旦赋值,以后就不能改变了)//和conste一样,来定义常量.final修饰的变量有两次赋值的机会:申请变量的时候,在构造函数中。
package test;
package test;
publicclass TestFinal {
publicstaticvoid main(String[] args) {
ClassA cs = new ClassA();
System.out.println(cs.B); // 这样会编译错误. 没有初始化,因为final要进行初始化。
cs.B = 10; // 无法为最终变量B指定值.因此要在创建对象时赋值。.
}
}
class ClassA {
finalint B; // 如果,加了final 默认值无效. 因为是常量所以要是大写.
finalint B = 10;// 第一种赋值的方法.
public ClassA(){}
public ClassA(int b) { // 第二种赋值方法.
this.B = B;
}
publicvoid m() {
int a = 10;
a = 20;
}
}
2. final 修饰类和方法.
例子: 修饰类,则这个类没有子类,如果一个类用final修饰,那么这个类不能被继承.
final class Super{ //编译错误, 无法从最终类继承.例子: String 类是一个final类.
public final void m(){} // 如果一个类用final修饰,那么这个类不能被继承.
}
//final 的用处: 自己写的方法,不希望被子类修改,保持了方法的稳定性.
class Sub extends Super{
public void m(){}//编译错误.无法覆盖因为被覆盖的方法是 final.
}
//判断: 一个final类的其中所有的方法全是final ????? 对了,呵呵.
public static final double A=3.14//公开静态常量.
======================================================================
package test;
2. final 修饰类和方法.
例子: 修饰类,则这个类没有子类,如果一个类用final修饰,那么这个类不能被继承.
final class Super{ //编译错误, 无法从最终类继承.例子: String 类是一个final类.
public final void m(){} // 如果一个类用final修饰,那么这个类不能被继承.
}
//final 的用处: 自己写的方法,不希望被子类修改,保持了方法的稳定性.
class Sub extends Super{
public void m(){}//编译错误.无法覆盖因为被覆盖的方法是 final.
}
//判断: 一个final类的其中所有的方法全是final ????? 对了,呵呵.
public static final double A=3.14//公开静态常量.
======================================================================
package test;
publicclass TestFinal {
publicstaticvoid main(String[] args) {
ClassA cs = new ClassA();
System.out.println(cs.A);// 编译器在编译的时候System.out.println(10);10
// 是静态常量.因此不会加载ClassA();
System.out.println(cs.B);// 编译器在编译的时候不能确定B的值,因此会加载ClassA();
}
}
class ClassA {
static {
System.out.println("Load ClassA");
}
publicstaticfinalintA = 2 * 5;//编译器能确定,因此就不装载子类了。
publicstaticfinaldoubleB = Math.random();//编译器不能确定此时的值,因此要装载子类。
}
======================================================================
(14) abstract 表示抽象的 修饰类,方法,抽象类:用来被继承.
抽象方法:只有定义没有实现.如果一个类里边有抽象方法,这个类必需是抽象类.一个抽象类,并不一定有抽象方法.
抽象类有构造方法
通过abstract,我们可以把一个方法定义
例子:
package test;
======================================================================
(14) abstract 表示抽象的 修饰类,方法,抽象类:用来被继承.
抽象方法:只有定义没有实现.如果一个类里边有抽象方法,这个类必需是抽象类.一个抽象类,并不一定有抽象方法.
抽象类有构造方法
通过abstract,我们可以把一个方法定义
例子:
package test;
publicclass TestAbstact{
publicstaticvoid main(String[] args){
Super s=new Super();// 是抽象的不能去创建对象,因此不能作为运行时类型.
Super s;// 可以声明引用.他是用来被继承的.
Super s=new Sub();// 可以,抽象类可以作为一个类的半成品.(抽象类作为编译时类型,子类作为运行时类型.)
s.m();// 找子类中实现的方法.
}
}
abstractclass Super{
publicabstractvoid m(); // 抽象方法,只有声明没有实现.
}
class Sub extends Super{// 如果不实现他,就不会编译通过,嘻嘻,必需全部实现父类的抽象方法.
publicvoid m(){
System.out.println("hehe"); // 实现了父类的这个方法.呵呵.
}
}
final abstract 都不能修饰构造方法.
======================================================
(14) 修饰符的组合方式;final abstract 都不能修饰构造方法.
抽象类,可以有构造方法,是让子类调用的.
但是,接口没有构造方法.
private ,static,final 可以任意的组合,去修饰一个方法.
三个任意一个都不能和abstract 和用在一起.
private
static 不能混用 abstract
final
---------------------------------------------
抽象方法的作用:
======================================================================
(15) 接口语法:
1. 一个接口就是一个抽象类,而且是一个特殊的抽象类,所有属性默认都是公开静态常量,所有的方法默认都是公开抽象方法.接口之间可以多继承.一个类在继承另外一个类的同时,还可以实现多个接口,
2. 一个类实现一个接口,如果这个类不是抽象类的化,那么就一定要实现接口中定义的方法.
3. 接口没有构造方法.
例子:
package test;
final abstract 都不能修饰构造方法.
======================================================
(14) 修饰符的组合方式;final abstract 都不能修饰构造方法.
抽象类,可以有构造方法,是让子类调用的.
但是,接口没有构造方法.
private ,static,final 可以任意的组合,去修饰一个方法.
三个任意一个都不能和abstract 和用在一起.
private
static 不能混用 abstract
final
---------------------------------------------
抽象方法的作用:
======================================================================
(15) 接口语法:
1. 一个接口就是一个抽象类,而且是一个特殊的抽象类,所有属性默认都是公开静态常量,所有的方法默认都是公开抽象方法.接口之间可以多继承.一个类在继承另外一个类的同时,还可以实现多个接口,
2. 一个类实现一个接口,如果这个类不是抽象类的化,那么就一定要实现接口中定义的方法.
3. 接口没有构造方法.
例子:
package test;
publicclass TestInterface{
publicstaticvoid main(String[] args){
Impl i=new Impl();
MyClass mc=i;
mc.m6();// 只能调用m6();
IA ia=i;ia.m1();ia.m2();
IB ib=i;ib.m3();
IC ic=i;ic.m1();ic.m2();ic.m3();ic.m4();
ID id=i;is.m5();
}
}
abstractclassAbstractClass{ // 接口是特殊的抽象类
publicabstractvoid m1();
}
class Sub extends Super{
publicstaticfinalintA=10;
publicabstractvoid m1();
publicabstractvoid m2();
}
interface IA{ // 此接口和上一个抽象类在逻辑上是完全等价的.
inta=10;// 接口的属性.接口中属性公开静态常量.
// 接口中没有构造方法.
void m1();// 接口中所有的方法都是公开抽象方法.
void m2();
}
interface IB{//
void m3();
}
interface IC extends IA,IB{// 接口能够继承.而且能够多继承.
void m4();
}
interface ID{ //
void m5(); //
}
class Impl extends IA{ // 错误,类和类之间有继承,接口和接口之间有继承,类和接口之间只有实现.
}
class Impl implements IA{// 实现接口也要实现里面的抽象方法.
void m1(){}// 编译不通过
publicvoid m1(){} // 这样才能编译通过,嘻嘻.
publicvoid m2(){}// 这样才能编译通过,嘻嘻.
}
abstractclass MyClass{
publicvoid m6() {
}
}
class Impl extends MyClass implements IC,ID{// 这样会绕过单继承的限制,而且可以继承多个接口.
publicvoid m1(){} publicvoid m2(){}publicvoid m3(){}publicvoid m4(){}publicvoid m5(){}
publicvoid m6(){}
}
class Sub extends Super{
publicabstractvoid m1();publicabstractvoid m2();
}
class Super{
}
======================================================================
以下是老师的笔记:
以下是老师的笔记:
static
属性 类变量 全类共有 类加载时创建,类名访问
方法 类名调用,静态方法中不能访问类的非静态成员,可以覆盖,只能被静态方法覆盖,没有多态
初始代码块 类加载时运行
类加载:
一个类编译之后会形成.class文件,储存了类的全部信息。当JVM第一次需要用到这个类的时候,会根据ClassPath找到这个.class文件,用输入流把文件中的信息读入JVM并保存起来,这样,JVM就“认识”了这个类
类加载时机:第一次用这个类的时候
1. 第一次创建类的对象,会加载
2. 访问类的静态成员,会加载
3. 声明类的引用,不会加载
4. 加载子类,必然先加载父类
5. 如果调用的是子类从父类中继承到的静态方法,只会加载父类
6. 如果访问的是类的静态常量,如果在编译的时候能够确定这个常量的值,则运行时不会加载,否则,编译时无法确定常量值,那么运行时就会加载
设计模式:单例模式
用途:一个类只能有一个对象
实现:会有一个静态的属性,就是该类的一个对象。提供一个静态方法,来获得这个唯一的静态属性(单例),同时构造方法私有
final
变量:常量,一旦赋值,不能改变,为属性常量赋值的时机:对于实例常量,初始化或者构造方法中可以赋值;对于类常量,初始化或者静态初始代码块中可以赋值
方法:不能被覆盖
类 :不能被继承
abstract
方法:只有定义,没有实现
类:不能构造对象,但可以用来声明一个引用(作为编译时类型)
如果一个类有抽象方法,这个类必须是抽象类,如果一个类是抽象类,不一定有抽象方法
子类继承一个抽象类,就必须覆盖(实现)父类(抽象类)中的所有抽象方法,否则,子类就也得是抽象类
抽象类有构造方法
通过abstract,我们可以把一个方法的定义放在父类,而留给子类实现。
接口
一个接口是一个特殊的抽象类。所有的属性默认都是公开静态常量,所有的方法默认都是公开抽象方法
接口之间可以多继承
一个类在继承另外一个类的同时,还可以实现多个接口。而实现的每一个接口都将成为这个类的兼容类型,允许多态的使用
一个类实现一个接口,如果这个类不是抽象类的话,那么就一定要实现接口中定义的所有方法
接口没有构造方法
接口的作用:
1.实现多继承
区分主类型和次要类型,接口的引入就使得我们可以对事物的共性作一个再抽象,抽象出副类型。
这种多继承的关系不会破坏类之间单继承树状关系的复杂度
2.标准
标准的制定者、实现者、使用者分离
解耦合的工具
标准的使用者和标准的实现者通过接口实现弱耦合
属性 类变量 全类共有 类加载时创建,类名访问
方法 类名调用,静态方法中不能访问类的非静态成员,可以覆盖,只能被静态方法覆盖,没有多态
初始代码块 类加载时运行
类加载:
一个类编译之后会形成.class文件,储存了类的全部信息。当JVM第一次需要用到这个类的时候,会根据ClassPath找到这个.class文件,用输入流把文件中的信息读入JVM并保存起来,这样,JVM就“认识”了这个类
类加载时机:第一次用这个类的时候
1. 第一次创建类的对象,会加载
2. 访问类的静态成员,会加载
3. 声明类的引用,不会加载
4. 加载子类,必然先加载父类
5. 如果调用的是子类从父类中继承到的静态方法,只会加载父类
6. 如果访问的是类的静态常量,如果在编译的时候能够确定这个常量的值,则运行时不会加载,否则,编译时无法确定常量值,那么运行时就会加载
设计模式:单例模式
用途:一个类只能有一个对象
实现:会有一个静态的属性,就是该类的一个对象。提供一个静态方法,来获得这个唯一的静态属性(单例),同时构造方法私有
final
变量:常量,一旦赋值,不能改变,为属性常量赋值的时机:对于实例常量,初始化或者构造方法中可以赋值;对于类常量,初始化或者静态初始代码块中可以赋值
方法:不能被覆盖
类 :不能被继承
abstract
方法:只有定义,没有实现
类:不能构造对象,但可以用来声明一个引用(作为编译时类型)
如果一个类有抽象方法,这个类必须是抽象类,如果一个类是抽象类,不一定有抽象方法
子类继承一个抽象类,就必须覆盖(实现)父类(抽象类)中的所有抽象方法,否则,子类就也得是抽象类
抽象类有构造方法
通过abstract,我们可以把一个方法的定义放在父类,而留给子类实现。
接口
一个接口是一个特殊的抽象类。所有的属性默认都是公开静态常量,所有的方法默认都是公开抽象方法
接口之间可以多继承
一个类在继承另外一个类的同时,还可以实现多个接口。而实现的每一个接口都将成为这个类的兼容类型,允许多态的使用
一个类实现一个接口,如果这个类不是抽象类的话,那么就一定要实现接口中定义的所有方法
接口没有构造方法
接口的作用:
1.实现多继承
区分主类型和次要类型,接口的引入就使得我们可以对事物的共性作一个再抽象,抽象出副类型。
这种多继承的关系不会破坏类之间单继承树状关系的复杂度
2.标准
标准的制定者、实现者、使用者分离
解耦合的工具
标准的使用者和标准的实现者通过接口实现弱耦合