5、继承
1 //Java中所有对象都显式/隐式的继承子Object类 2 class fu{ 3 fu(){ 4 System.out.println("fu..."+getNum()); 5 show(); 6 } 7 private int num=3; 8 public void setNum(int num){ 9 this.num=num; 10 } 11 public int getNum(){ 12 return num; 13 } 14 public void show(){ 15 System.out.println("这是fu类的show方法"); 16 } 17 } 18 /*0、继承表示两个类之间产生关系,用extends标示。注意子类不能继承父类中私有的属性,但是也可以通过公开方法访问 19 * 继承中有三个部分的问题: 20 * 1、成员变量的继承 21 * 2、成员方法的继承 22 * 3、构造函数的继承 23 */ 24 class zi extends fu{ 25 zi(){ 26 /*3、java中在子类的构造函数开始有一个隐藏操作:super(),这是为了对父类进行初始化操作,便于操作继承来的属性 27 * 和this()调用本类(无参)构造函数相似,super()可以调用父类的(无参)构造函数 28 * !!!注意默认情况下调用父类的无参构造函数 29 * !!!如果没有无参构造函数/需要传入参数,必须显式的使用super(args),调用对应有参构造函数 30 * !!!且super(args)必须定义在子类构造函数的第一句(this()也同样需要定义在第一行) 31 */ 32 System.out.println("zi"); 33 } 34 private int num=4; 35 int num2=5; 36 public void show(){ 37 int num=6; 38 /*1、变量的继承:一个函数块中使用的变量会在三个地方查找 39 * 1、函数块内,是局部变量 40 * 2、当前类内,成员变量 41 * 3、继承的类内,继承变量 42 * 如果没有指明,则以上面的顺序查找到的变量为准;当然也可以指明(this->本类对象,super->父类空间) 43 * !!!但是像这种子类和父类中使用同名变量的情况几乎不存在,因为既然在父类中定义就表明是共性内容, 44 * !!! 就不需要在子类中在进行操作 45 */ 46 System.out.println("函数块内num="+num+",类内num="+this.num+",父类中num="+super.getNum()); 47 /*2、方法的继承: 48 * !!!1、如果子类中没有同名方法:使用父类中的方法,并且运行环境是在父类 49 * !!! (用this调用变量是在父类,但是如果调用方法仍然是先找子类) 50 * 2、如果类中有同名方法:父类方法被覆盖,所以使用子类中方法,可以用super来指向父类对象。 51 */ 52 super.show(); 53 } 54 } 55 56 public class ObjectExtend { 57 public static void main(String[] args){ 58 zi z=new zi(); 59 z.show(); 60 } 61 }
1 public class Test { 2 public static void main(String[] args){ 3 zilei z=new zilei(); 4 } 5 } 6 class fulei{ 7 private int num=3; 8 9 public int getNum() { 10 this.show(); 11 return num; 12 } 13 14 public void setNum(int num) { 15 this.num = num; 16 } 17 public void show(){ 18 System.out.println("fulei"); 19 } 20 } 21 class zilei extends fulei{ 22 private int num=4; 23 /* 24 public int getNum() { 25 return num; 26 } 27 public void setNum(int num) { 28 this.num = num; 29 } 30 */ 31 zilei(){ 32 //这里调用getNum方法,子类中没有所以在父类中找;而父类该方法调用了show(),子类中有所以用子类的 33 System.out.println(this.getNum()); 34 } 35 public void show(){ 36 System.out.println("zilei"); 37 } 38 }
5.1、构造函数
java对象的构造函数有一定的特殊性:
1、每一个函数都必须至少有一个构造函数,如果没有,那么Java编译器会为我们自动生成一个构造函数
2、Java要求一个对象被初始化之前,其超类也必须被初始化,这一点是在构造函数中保证的。Java强制要求Object对象(Object是Java的顶 层对象,没有超类)之外的所有对象构造函数的第一条语句必须是超类构造函数的调用语句或者是类中定义的其他的构造函数(并且调用的构造函数只能有一个,因为它们必须为第一句,有两个则引起冲突),如果我们即没有调用其他的构造函数,也没有显式调用超类的构造函数,那么编译器会为我们自动生成一个对超类构造函数的调用指令
参考:http://blog.jobbole.com/23939/
6、抽象类和接口:
1 /*有两类特殊的继承:抽象类(abstract class)和接口(interface),都是在向上抽离类的过程中出现的, 2 * 抽象类和普通类相似,只是包含抽象类而已,由abstract标示,!!!并且不能实例化,但是可以初始化 3 * 接口使用interface,不需要使用class,方法全都是抽象方法,同样不能实例化 4 * 5 * ☆注意:实例化和初始化的区别: 6 * 实例化是用new进行的,并将产生的对象首地址返回给变量以供操作 7 * 初始化是指将已存在的对象空间的变量进行赋值的过程,由jvm执行 8 * !!!综上:抽象类可以进行初始化是由jvm开辟一片内存空间,来进行初始化操作,但是不能由用户进行new操作 9 * !!!所以抽象类中可以使用this访问其中的属性 10 */ 11 public class ObjectExtend2 { 12 public static void main(String[] args){ 13 Programmer p=new Programmer("asd",1,5000); 14 p.work(); 15 } 16 } 17 18 /*其中的抽象方法没有方法体,并且用abstract修饰;类中有抽象方法,该类也必须用abstract修饰。 19 * 因为抽象类中有没有实现的方法,所以不能实例化;并且只有其子类将所有的抽象方法实现才能实例化 20 */ 21 /*下面是一个抽象类例子: 22 * 需求:公司中程序员有姓名,编号,工资等属性,行为是工作->写代码;还有经理除了上述属性还有奖金,行为是工作->管理。 23 * 对给出的需求进行数据建模 24 */ 25 abstract class Employee{ 26 private String name; 27 private int id; 28 private double pay; 29 public abstract void work(); 30 Employee(String name,int id,double pay){ 31 this.name=name; 32 this.id=id; 33 this.pay=pay; 34 } 35 public void setName(String name){ 36 this.name=name; 37 } 38 public String getName(){ 39 return name; 40 } 41 public void setId(int id){ 42 this.id=id; 43 } 44 public int getId(){ 45 return id; 46 } 47 public void setPay(int pay){ 48 this.pay=pay; 49 } 50 public double getPay(){ 51 return pay; 52 } 53 } 54 55 class Programmer extends Employee{ 56 Programmer(String name,int id,double pay){ 57 super(name,id,pay); 58 } 59 public void work(){ 60 System.out.println("I'm "+this.getName()+",and is the "+this.getId()+" employee,for "+this.getPay()+"money,i'm coding..."); 61 } 62 } 63 64 class Manage extends Employee{ 65 private int bonus; 66 Manage(String name,int id,double pay,int bonus){ 67 super(name,id,pay); 68 this.setBonus(bonus); 69 } 70 public int getBonus() { 71 return bonus; 72 } 73 public void setBonus(int bonus) { 74 this.bonus = bonus; 75 } 76 public void work(){ 77 System.out.println("manage!"); 78 } 79 } 80 81 /*接口中常见的成员包括:1、全局常量,2、抽象方法 82 * !!!类与类(包括抽象类)之间的关系为继承extends;类与接口之间的关系为实现implements; 83 * !!!接口与接口之间是继承关系(extends),而且只有在继承接口是可以多继承 84 * 接口中的抽象方法必须都实现,才能被实例化,否则是抽象子类 85 * 接口的一个优点是可以多实现,间接实现了多继承。这是因为即使实现的多个接口中有同名方法,它们都没有方法体, 86 * 而是由实现类完成的,所以无所谓 87 * !!!继承(extends)和接口(implements)可以同时进行 88 */ 89 interface Demo1{ 90 public static final int NUM=4; 91 public abstract void show1(); 92 public abstract void show2(); 93 } 94 95 interface Demo2{ 96 public abstract void show3(); 97 public abstract int show4(int a,int b); 98 } 99 100 class DemoImpl extends Programmer implements Demo1,Demo2{ 101 DemoImpl(String name,int id,double pay){ 102 super(name,id,pay); 103 } 104 public void show1(){ 105 106 } 107 public void show2(){ 108 109 } 110 public void show3(){ 111 112 } 113 public int show4(int a,int b){ 114 return a+b; 115 } 116 }
7、多态:
!!!多态的一个特点就是在参数需要接收父类的地方,可以用子类代替,进行了默认的类型提升。此时访问成员变量的环境在父类中,访问成员函数同样会发生覆盖。
1 public class ObjectPolymorphism { 2 public static void main(String[] args){ 3 /*java中的多态简单来说就是一个对象对应着不同的类型(可以是本类类型,父类类型,实现的接口类型) 4 * 像下面的Dog对象转为Animal对象是类型提升/向上转型 5 * 当然转换后的类型也可以强制转换为Dog对象,但是不能强制转换为其他子类 6 */ 7 Animal dog=new Dog(); 8 /*dog1=(Dog)dog; 经过类型提升的对象才可以向下转型,若原来就是父类对象,就不允许向下转型 9 * cat=(Cat)dog; 不同类型不允许强制转换 10 */ 11 eat(dog); 12 work(dog); 13 } 14 /*多态是应对Java强类型语言在对象作为参数传递时的局限性, 15 * 例如下面,不同动物有不同的eat方法,如果只能传入具体动物类,则每个动物都需要写一个相应eat方法 16 * 但是内部的操作是一样的,所以只需传入父类类型即可,实现时根据具体的动物类型,调用其内部的eat方法。 17 */ 18 public static void eat(Animal a){ 19 a.eat(); 20 } 21 /*public static void eat(Cat c){ 22 * c.eat(); 23 * } 24 *public static void eat(Dog d){ 25 * d.eat(); 26 * } 27 */ 28 public static void work(Animal a){ 29 /*如果要判断具体的类型,可以使用instanceof关键字, 30 * 31 */ 32 if(a instanceof Cat){ 33 Cat c=(Cat)a; 34 c.catchMouse(); 35 }else if(a instanceof Dog){ 36 Dog d=(Dog)a; 37 d.kanjia(); 38 } 39 } 40 41 } 42 abstract class Animal{ 43 abstract void eat(); 44 } 45 class Cat extends Animal{ 46 void eat(){ 47 System.out.println("吃鱼"); 48 } 49 void catchMouse(){ 50 System.out.println("捉老鼠"); 51 } 52 } 53 class Dog extends Animal{ 54 void eat(){ 55 System.out.println("啃骨头"); 56 } 57 void kanjia(){ 58 System.out.println("看家"); 59 } 60 }
!!!注意:静态方法在静态区,不能覆盖
8、内部类:
1 public class InnerClass { 2 public static void main(String[] args){ 3 //通过外部类访问内部类,是在外部类中产生的内部类 4 outer o=new outer(); 5 o.function(); 6 o.function1(); 7 o.function2(); 8 //!!!上面方法的一种变形,就是把产生内部类的过程放在外面 9 outer.inner i=new outer().new inner(); 10 /*如果内部类是static修饰的,外部类一加载就存在了,所有访问时不需要创建外部类对象,即: 11 *outer.inner i=new outer.inner(); 12 */ 13 i.show(); 14 } 15 16 } 17 class outer{ 18 private int num=3; 19 //内部类:和js中的作用域链有点类同,就是本类中如果没有,会向外部寻找,但是依然有权限限制,如果外部是private,则只能在inner类的内部进行访问 20 //内部类的修饰符:private->只能在包含类中访问,外部不能访问;static->相当于外部类,访问情况见下 21 class inner{ 22 private int num=4; 23 void show(){ 24 int num=5; 25 //内部类与外部类变量重名时的访问 26 System.out.println("num="+num); //访问局部成员 27 System.out.println("this.num="+this.num); //访问内部类成员变量 28 //=System.out.println("inner.this.num="+inner.this.num); 29 System.out.println("outer.this.num="+outer.this.num); //访问外部类成员变量 30 } 31 } 32 void function(){ 33 inner i=new inner(); 34 i.show(); 35 } 36 void function1(){ 37 /*局部内部类:是将内部类定义在局部环境中,!!!如果此时内部类访问局部变量,需要使用final 38 * 这是因为Java是一种严谨的语言,考虑到了特殊的情况: 39 * 就是下面注释中展示的不是直接操作内部对象,而是将其返回到外部,然后进行操作,如果此时调用内部变量, 40 * 外部将报错,所以需要使用final修饰,使其永远可以访问 41 */ 42 final int NUM=6; 43 class inner{ 44 void say(){ 45 System.out.println("NUM="+NUM); 46 } 47 } 48 inner i=new inner(); 49 i.say(); 50 /*public inner getInnerObject(){ 51 * inner i=new inner(); 52 * return i; 53 *} 54 */ 55 } 56 void function2(){ 57 /*下面是一个匿名内部类的例子,直接创建一个父类/接口对象, 58 * 和对象不同的是有{}包含的抽象方法实现,这就是一个子类的匿名形式, 59 * 但是返回值是一个对象,如果要调用多个方法,可以用一个变量接收这个对象 60 * !!!注意接收这个对象的类型只能是父类的类型,此时向上转型,只能调用父类中有的方法 61 */ 62 Inner i=new Inner(){ 63 public void show1(){ 64 System.out.println("这是匿名内部类方法1"); 65 } 66 public void show2(){ 67 System.out.println("这是匿名内部类方法2"); 68 } 69 }; 70 i.show1(); 71 i.show2(); 72 } 73 } 74 abstract class Inner{ 75 abstract void show1(); 76 abstract void show2(); 77 }
总结:对象的初始化过程:
参考:http://mysun.iteye.com/blog/1596959
知识:设计模式。参考:http://zz563143188.iteye.com/blog/1847029
1 public class Singletion { 2 public static void main(String[] args){ 3 Singletiontest2 s1=Singletiontest2.getInstance(); 4 Singletiontest2 s2=Singletiontest2.getInstance(); 5 s1.setNum(10); 6 s2.setNum(20); 7 System.out.println(s1.getNum()==s2.getNum()); 8 System.out.println(s1.equals(s2)); 9 } 10 } 11 /*下面是一个简单的类,有一个私有属性,并提供了访问方式, 12 *如果现在又需求:只能产生一个类对象,产生过多则会浪费空间 13 *此时就可以进行单例模式设计 14 */ 15 class Singletiontest{ 16 private int num; 17 public int getNum() { 18 return num; 19 } 20 public void setNum(int num) { 21 this.num = num; 22 } 23 } 24 /*只要满足以下三个步骤就可以构成单例模式 25 * 1、其他类中不能通过new产生对象 --》将构造函数私有化 26 * 2、必须在本类中产生一个对象 --》在本类中new一个对象,并用私有属性保存 27 * 3、必须有一个方法将产生的对象提供出去以便其他类操作 --》将这个私有属性值返回调用处 28 * 注意: 29 * 单例是用类生成对象,所以生成对象的过程中所使用的都需要是static; 30 * 并且在获取对象过程中不能使用this关键字,之后由对象操作的部分才可以使用 31 */ 32 class Singletiontest2{ 33 private Singletiontest2(){} 34 private static Singletiontest2 instance=new Singletiontest2(); 35 public static Singletiontest2 getInstance(){ 36 return Singletiontest2.instance; 37 } 38 private int num; 39 public int getNum() { 40 return num; 41 } 42 public void setNum(int num) { 43 this.num = num; 44 } 45 } 46 /*单例模式的延迟加载写法:区别在于没有在加载时直接创建对象(static属性会在类加载时建立) 47 *而是在调用getInstance()时判断是否需要new 48 */ 49 class Singletiontest3{ 50 private Singletiontest3(){} 51 private static Singletiontest3 instance=null; 52 public static Singletiontest3 getInstance(){ 53 if(instance==null){ 54 instance=new Singletiontest3(); 55 } 56 return instance; 57 } 58 private int num; 59 public int getNum() { 60 return num; 61 } 62 public void setNum(int num) { 63 this.num = num; 64 } 65 }