简介
1,组合语法
public class Car { private String name,version; //初始化给变量赋值 private int size=10; private CarEngines engines; //构造器给变量赋值 public Car(String name,String version,int size,CarEngines engines){ this.name=name; this.version=version; this.size=21; engines=new CarEngines(); } //代码块赋值 { this.name="qq"; this.version="zx1.0.0"; this.size=12; engines=new CarEngines(); } //利用引擎类启动 public void run(){ engines.run(); } //利用引擎类关闭 public void close(){ engines.close(); } //set方法给变量赋值 public void setName(String name) { this.name = name; } public void setVersion(String version) { this.version = version; } public void setSize(int size) { this.size = size; } public void setEngines(CarEngines engines) { this.engines = engines; } } /** * 汽车引擎 */ class CarEngines{ public void run(){ System.out.println("启动汽车"); } public void close(){ System.out.println("关闭汽车"); } }
从代码示例中可以看到,给变量赋值有很多种方式,根据示例情况赋值,例如set方法可以在运行中为某个实例赋n次值,而通过构造器只能为某个实例赋一次值。
2,继承语法概念
//父类 public class Father { private String name="lalalala"; public int size; public String common="f1"; public Father(int i){ System.out.println(i); } public void print(){ System.out.println("name:"+name); } public void printSize(){ System.out.println("fffff"); } } //子类 public class Child extends Father { public String common="c1"; public Child(){ super(1);//必须执行,不然会报错, /** * 参数的时候需要明确执行,无参的时候是程序隐式执行父构造器 * 也就是说子类构造器构造执行时必须先执行父构造器,不然就会报错 */ } public void printName(){ //可以直接调用父类方法 print(); } @Override public void printSize(){ System.out.println("ccccc"); } public void setSize(){ this.size=123;//可以直接使用父类允许访问权限的域和方法 //this.name 那么在父类中设置为private私有的, 所以子类服务继承使用 } /** * 父类和子类同时拥有的方法和变量名称时,在通过子类调用时如下: * 默认调用则是调用子类的域和方法,默认调用其实也是this调用 * 指定super调用则是调用父类的域和方法。 * 通过this调用则是调用子类本身的域和方法。 */ @Test public void show(){ System.out.println("defult:"+common+",father:"+super.common+",child:"+this.common); printSize(); super.printSize(); this.printSize(); //结果: //defult:子类.common,father:父类.common,child:子类.common //子类:printSize方法 //子类:printSize方法 //父类:printSize方法 } }
注意。初始化的时候先初始化父类的静态(按顺序),再初始化子类的静态(按照顺序),再初始化父类的成员变量,构造块,最后再初始化父类的构造器,之后再初始化子类的成员变量,构造块,再初始化子类的构造器。详情请看笔记《02-方法传参和初始化与垃圾回收清除》初始化部分。
3,向上转型
//方法参数是父类类型 public static void printSizeByFather(Father f){ f.printSize();//输出结果是子类实例内容,即“子类:printSize方法” } public static void main(String[] args) { printSizeByFather(new Child());//传入的子类实例 }
父类引用可以指向子类实例,也可以将父类作为参数子类传入参数,java通过RTTI类判断具体是哪个子类实例还是父类实例。
4,final关键字
4.1 空白final常量
/** * TODO 测试final空白变量(什么final并没实现赋值)什么时候可以赋值。 * 结果在普通方法中无法赋值,而再构造器方法中可以赋值 */ private final Hello hello; private final Hello hello2=new Hello(); //普通方法 public void isMethodCreateFinal(){ //hello=new Hello(); 编译不通过。无法赋值 } //构造器方法 public Handler(){ hello=new Hello();//可以赋值 //hello2=new Hello(); 构造器只能对未赋值的final变量赋值,但不能改值,编译器报错 }
final的空白变量可以用构造器赋值。但是已经赋值的final常量则不能再更改了,而其他方法时不能给构造器赋值,原因是因为构造器只会执行一次,也符合final变量不能改变的原则。
//可变对象 public class Handler { private int n; public Handler(int n){ this.n=n; } public void show(){ if (n!=n){ System.out.println("线程不安全"); } } } //不可变对象 class HandlerFinal{ private final int n; public HandlerFinal(int n){ this.n=n; } public void show(){ System.out.println("线程安全"); } }
对象可变与否,是看对象的状态即变量是不是可以共享以及可以被修改,示例中Handler类和Handler类只有一个基本类型的n变量,而且更改n变量只能通过构造方法才可以,但由final修饰的n才是不可变对象,对象实例化操作不是原子性的,上面有替代new对象时,会分为好几个步骤,比如先初始化静态变量以及父类变量等等,最后才实例化对象。试想下,但java对final修饰的变量做了特殊处理,导致final修饰的变量可以实现其不可变性,即线程安全。
4.2 final参数
/** * TODO final 方法参数 * @param i */ public void finalParam(final Integer i){ System.out.println(i); //i=new Integer(3);可以读但无法修改final参数,否则编译器不通过,常用于匿名内部类 } @Test public void finalParamRun(){ /** * 可以正常传不同值 */ finalParam(new Integer(3)); finalParam(new Integer(5)); }
此时的方法参数map由final修饰,就是final方法。final方法参数能够传不同的值,但不能修改参数,否则报错
4.3 final方法
class FinalMethod{ public final void finalMethod(){ System.out.println(); } public void method(){ System.out.println(); } }

final和private的区别?
4.4 final类
final class FinalClass{ }
尝试继承结果:

5,总结: