标签:
一、回到前言那一章,关于复用,java中直接提供的两种方式:组合和继承
1.关于组合:类中创建新的类的对象
关于这一点,组合是类似积木的方式,其实相比于继承来说松耦性更好,在了解spring后,会知道spring提出的控制反转,对于这种积木方式又是进一步解耦。
2.关于继承,这是java中的一个特点,同时也是多态的基础
1)注意一个细节
1 public class Test extends Check{
2 String s ;
3 public static void main(String[]args) {
4 Test t = new Test();
5 t.f();
6 }
7 @Override
8 public void f() {
9 f();//这里的原意是调用父类f(),但是忘记写super
10 }
11 }
12
13 class Check{
14 public void f() {
15 System.out.println("我是父类的f()");
16 }
17 }
结果如下:
因为忘记写super,形成无限迭代调用当前子类的f(),报错。
2)继承中的创建对象:创建子类对象会先创建其父类对象
注意下例:
1 package com.zk.ant;
2
3 class Father {
4 int i;
5 public Father(int i) {
6 this.i = i;
7 }
8 }
9
10 class Son extends Father {//这里报错
11
12 }
13
14 public class Test {
15 public static void main(String[]args) {
16 }
17 }
这里Son处,编译会报错,因为父类只写了有参构造方法,但是子类没有写,子类默认采用无参构造方法,而子类无参构造方法又去默认调用父类的无参构造方法,发现找不到父类的无参构造方法,所以编译期间就报错。
3)关系到继承的情况下,在清理的时候需要注意:(可以参见第三篇创建与清理)
子类的finalize()方法如果要重写,需要在重写的方法里面显式调用父类 super.finalize()
4)子类中方法,如果是和父类中某个方法同名但是参数类型、个数不同,则构成重载关系;
子类中方法如果完全和父类中某个方法相同,则构成覆盖关系
基于这一点,如果想要在子类中覆盖某个父类方法,最好加上@Override,避免不小心名字写错了造成不必要的麻烦
二、关于代理(关于代理模式的详解,放在下一章节)
在java的语言层次,直接提供的复用类关系就是组合和继承。在它们之间,有一种代理关系, 代理将一个成员对象置于所要构造的类中(这点就像组合),同时又在新类中暴露原来的类的方法(这点就像继承),见下例:
1 public class Test extends A {
2 A a = new A();//将A对象插入到Test中作为成员变量,这点类似组合
3 @Override
4 public void f() {//可以看到Test继承A,暴露出A的方法
5 a.f();
6 //可以新增拓展功能
7 }
8 }
9
10 class A{
11 public void f() {
12 System.out.println("ff");
13 }
14 }
三、java中权限
同类 | 同包 | 父子 | 无关系 | |
public | Y | Y | Y | Y |
protected | Y | Y | Y | N |
defualt | Y | Y | N | N |
private | Y | N | N | N |
上面是java中的四种访问修饰符及权限关系,注意的两点:
对于类来说,只能用public和default;
对于继承来说,子类会继承父类的全部元素,包括私有元素,只是子类不能够使用父类的私有元素
1. 在继承中,权限的作用域只能够放大或者不变,不能变小
1 public class Test{
2 public static void main(String[]args) {
3 B b = new B();
4 b.f();
5 }
6 }
7
8
9 class B extends A{
10 public void f() {
11 System.out.println("B类中的重载方法");
12 }
13 }
14
15 class A {
16 protected void f() {
17 System.out.println("A类中的重载方法1");
18 }
19 }
结果如下:
可以看到,B中的f方法将权限扩大了,还是会覆盖原来的A中的f() (仅限于default,protected,public)
需要注意的是,private的方法,默认就是final的,它不能够被继承
四、关于final关键字
1.数据用final修饰
用final修饰的数据,有两个地方:常量 ,static final 修饰 ,不想被修改的量,参数列表中加final
final修饰的数据,必须在使用前赋值(一般来讲是要声明时候就赋值,如果能够保证一定被赋值到,则可以在声明时不赋值),见下例:
1 public class Test{
2 private final int i=0;//一般来讲,final修饰的声明时候最好赋值
3 private final int j ;//这里声明的时候没有赋值
4 private final Poppet p;
5
6 public Test(){
7 j = 1;//因为在构造方法中给j赋值了,能够保证使用前已经被赋值
8 p = new Poppet(1);
9 System.out.println("Test()构造方法"+j);
10 }
11
12 public Test(int i) {
13 j = i;
14 p = new Poppet(i);
15 System.out.println("Test(i)构造方法"+j);
16 }
17 public static void main(String[]args) {
18 new Test();
19 new Test(2);
20
21 }
22 }
23
24
25 class Poppet {
26 private int i;
27 Poppet(int i1) {
28 this.i = i1;
29 }
30 }
上面的例子,如果注释掉 j = 1; 这一句,就会报错
结果如下:
再看一个关于final修饰的参数的例子:
1 public class Test{
2 public static void main(String[]args) {
3 Test t = new Test();
4 t.f(2);
5 Poppet p = new Poppet(22);
6
7 p.pp();//打印p中的i
8 t.t(p);//修改p中的i
9 p.pp();//再打印p中的i
10
11 }
12
13 public void f(final int i) {
14 System.out.println(i);
15 //i = 2;//报错,这里不能够修改i
16 }
17
18 public void t(final Poppet p) {
19 //p = new Poppet();//这里报错,因为p 被final修饰,不能够被改变
20 p.i = 3333;// 这里不会报错,因为被final修饰的p本身还是没变的,仍然指向那个对象,变化的是那个对象里面的i,那就跟final没直接关系了
21
22 }
23 }
24
25
26 class Poppet {
27 public int i;
28 Poppet(int i1) {
29 this.i = i1;
30 }
31 public void pp() {
32 System.out.println(i);
33 }
34 }
2.类用final修饰
用final修饰的类不能够被继承
标签:
原文地址:http://www.cnblogs.com/kaiguoguo/p/4676922.html