##继承
public class Person {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void showinfo() {
String i = "Person [age=" + age + ", name=" + name + "]";
System.out.println(i);
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public class Student extends Person {
private String school;
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public class test {
public static void main(String[] args) {
Student student=new Student();
student.setAge(22);
student.setName("田茂林");
student.setSchool("CUGB");
student.showinfo();
System.out.println(student.getSchool());
}
子类比父类大。子类可以继承父类的一切方法,成员变量,甚至是私有的,但是却不能够访问这些私有的成员变量和方法
###方法的重写
public void showinfo() {
String i = "Person [age= " + getAge() + ", name= " + getName() + " ,school= "+getSchool()+"]";
System.out.println(i);
}
重写的方法,覆盖掉原有方法,重写时最好copy父类里的方法,然后再改,重写方法不能使用比被重写方法更严格的访问权限
###super关键字
public class Father {
int value;
public void f(){
value=100;
System.out.println("我是父类"+100);
}
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public class Children extends Father {
int value;
public void f() {
value = 200;
super.f();
System.out.println("我是子类" + 200);
System.out.println(value);
System.out.println(super.value);
}
public static void main(String[] args) {
Children cc = new Children();
cc.f();
}
} //super指向父类
**输出结果为**:
我是父类100
我是子类200
200
100
###继承中的构造方法
class fatherclass {
int n;
public fatherclass() {
System.out.println("父类");
}
public fatherclass(int n) {
this.n = n;
System.out.println("父类" + n);
}
}
class childrenclass extends fatherclass {
int n;
public childrenclass() {
this(30); //调用父类的构造方法或者是通过this调用其它该类的构造方法,其它构造方法中会出现父类构造方法调用
System.out.println("子类");
}
public childrenclass(int n) {
super(200); //如果调用super构造方法,必须在第一行。
System.out.println("子类" + n);
}
}
public class Constructextends {
public static void main(String[] args) {
childrenclass ch1 = new childrenclass(); //子类的构造方法必须调用父类的构造方法,若没有显示的调用super,则默认调用父类无参的构造方法,若父类没有无参的构造方法,则报错。这里纠结的地方在于:类如果有显示构造方法,就会把原有的java自动赋予的无参空构造方法覆盖掉,如果父类什么都不写,是可以调用没问题的
childrenclass ch2 = new childrenclass(300);
}
}
**程序运行结果:**
父类200
子类30
子类
父类200
子类300
###代码分析
class Person{ //父类
private String name;
private String location;
public Person(String name) { //构造方法1
this.name=name;
this.location="beijing";
}
public Person(String name,String location) { //构造方法2
this.name=name;
this.location=location;
}
@Override
public String toString() {
return "Person [name=" + name + ", location=" + location + "]";
}
}
class Student extends Person{ //子类
private String school;
public Student(String name,String school) { //构造方法1
this(name,"beijing", school); //调用了该子类的构造方法2
}
public Student(String m,String n,String school){ //构造方法2
super(m,n); //调用了父类的构造方法
this.school=school;
}
public String toString() {
return "Student "+super.toString()+"school"+school;
}
}
public class Example1 { //测试类
public static void main(String[] args) {
Person p1=new Person("A");
System.out.println(p1.toString());
Person p2=new Person("B","shanghai");
System.out.println(p2.toString());
Student s1=new Student("C", "s1");
System.out.println(s1.toString());
Student s2=new Student("C", "shagnhai","s2");
System.out.println(s2.toString());
}
}
##object类
finalize()相当于c++里的析构函数,用于关闭打开的资源
clone()
equals(Object obj)与
getClass()反射机制,拿到的是自己编译好的class文件
hashcode()返回这个对象的哈希编码
public class TesttoString {
public static void main(String[] args) {
Dog d = new Dog();
System.out.println("d: " + d); // d: object.Dog@15db9742
// 类名@16位的哈希编码.toString方法在System.out.println()中会被自动调用,不用写方法调用也可以
}
}
=====================================================================
class Dog { // 该类默认继承object类和其所有方法
public String toString() {
return "wangwangwang";
}
}
用一张哈希表来记录对象在内存中的具***置,根据这个编码可以很快的找到这个对象所在的位置。一个码可以对应多个对象!
public class TestEqual {
public static void main(String[] args) {
Cat c1 = new Cat("red", 2, 3);
Cat c2 = new Cat("red", 2, 3);
System.out.println(c1 == c2); // 这里比较的是引用的地址,这两个地址不可能相同,所以只能是false
System.out.println(c1.equals(c2));// 默认的equals实现表示只有两个引用指向同一对象时候,返回值才是true。
// 所以一般要重写
String s1=new String("hello");
String s2=new String("hello");
System.out.println(s1==s2); //指向不同地址,所以是false
System.out.println(s1.equals(s2));//重写了String中的equals方法,所以内容相等
}
}
class Cat {
private String furColor;
private int height;
private int weight;
public Cat(String furColor, int height, int weight) {
this.furColor = furColor;
this.height = height;
this.weight = weight;
}
public boolean equals(Object obj) {
if (obj == null) {
return false;
} else if (obj instanceof Cat) { //用来判断是否是Cat类
Cat c = (Cat) obj;
if (c.furColor == this.furColor && c.weight == this.weight
&& c.height == this.height)
return true;
}
return false;
}
}
##内部类
l 一个文件里最好只有一个public类,该public类里还可以写public,即类内有类。
l **类的使用:**外部类直接实例化即可使用,实例化的外部类里边没有关于内部类的东西,基本上外部类的使用可以忽视内部类。//内部类的使用:先实例化new 外部类.new 内部类或者外部类对象.new 内部类
l 内部类可以直接访问并且调用外部类的字段,但优先执行本内部类内部的字段方法。执行顺序:本内部类方法------方法外-------外部类
l 外部类不能直接访问内部类,但可以通过实例化直接当成一个普通的数据类型一样访问。直接new 内部类
l 内部类不定义为public也默认设定为同一包可访问,如果想不同包也访问,必须定义为public类型。
l 外部类的所有字段无论是否private对于内部类都没有任何隐私可言
l 局部变量与成员变量相同的时候,成员变量被屏蔽,用this.成员变量来访问成员变量。
###局部内部类
定义在方法里面的类,一般很少用。奶牛和腿的关系,大类和小类的关系
###匿名内部类
l 匿名内部类没有类的名称,适用于只使用一次。
l 适用于父类和接口的继承情况!直接new 抽象类或接口,按照提示创建方法。
l 匿名内部类不能是抽象类,匿名内部类不能定义构造方法,只能直接用块儿去代替构造方法的作用。块儿比构造函数执行的还要超前,必须在实例化的时候才会出现,先执行静态初始化块,然后是初始化块儿,最后执行构造方法。
##对象转型
a instanceof Annimal a是不是动物类中的一个实例
public class Animal { //基类
public String name;
public Animal(String name) {
this.name = name;
}
}
class Dog extends Animal { //子类dog
public String furColor; //子类dog的属性furColor
public Dog(String n, String f) {
super(n);
this.furColor = f;
}
}
class Cat extends Animal { //子类Cat
public String eyeColor; //子类cat的新属性eyecolor
public Cat(String n, String e) {
super(n);
this.eyeColor=e;
}
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public class Test {
public static void main(String[] args) {
Animal a = new Animal("father");
Dog dog = new Dog("dogname", "red"); //后边new出来的是实际指向的,左边是可以实际访问的。
Cat cat = new Cat("catname", "blue");
System.out.println(a instanceof Animal);
System.out.println(dog instanceof Animal);//使用intaceof来判断该引用是否属于该类
System.out.println(cat instanceof Animal);
System.out.println(a instanceof Dog);
a = new Dog("a dog", "yellow"); //一个父类的引用类型变量可以指向其子类的对象//子类的对象可以当作父类的来使用,属于向上转型
System.out.println(a.name); //但是一个父类的引用类型变量不可以访问其子类对象新增方法与属性
Dog d=(Dog) a; //父类的对象当作子类来使用属于向下转型,强制转换。
System.out.println(d.name);
System.out.println(d.furColor);
}
}
程序运行结果:
true
true
true
false
a dog
a dog
yellow
public class Test2 {
public static void main(String[] args) {
Test2 t = new Test2();
Animal a = new Animal("father");
Dog d = new Dog("dogname", "blue");
Cat c = new Cat("Catname", "red");
t.f(d);
t.f(c);
}
public void f(Animal a) {
System.out.println(a.name);
if (a instanceof Dog) {
Dog d = (Dog) a;
System.out.println(d.furColor);
}
if (a instanceof Cat) {
Cat c = (Cat) a;
System.out.println(c.eyeColor);
}
}
}
程序运行结果:
dogname
blue
Catname
red
##多态
实际当中调用的方法是根据实际类型来分配的 Animal a=new Cat("",""),**也就是new的谁,指向谁,方法可以指向谁。 //如果没有多态机制,还得进行判断,传入的是什么类型,再强制转换,然后才能调用方法。**或者之间没有继承关系,每新增一个就要重新判断一次,重新执行一遍。
public class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
public void enjoy(){
System.out.println("动物叫声");
}
}
class Dog extends Animal { //要有继承
public String furColor;
public Dog(String n, String f) {
super(n);
this.furColor = f;
}
public void enjoy(){ //要有重写
System.out.println("狗叫声 ");
}
} //如果需要扩展动物叫声,只需要重新拓展一个类,重写一个方法即可
class Cat extends Animal {
public String eyeColor;
public Cat(String n, String e) {
super(n);
this.eyeColor=e;
}
public void enjoy(){
System.out.println("猫叫声");
}
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public class Lady {
private String name;
private Animal pet;
public Lady(String name,Animal pet) {
this.name=name;
this.pet=pet;
}
public void mypetenjoy(){
pet.enjoy();
}
public static void main(String[] args) { //可扩展性好意思就是main里的内容和结构基本不改变,只是添加即可
Animal a=new Animal("动物"); //根据实际运行情况来调用
Cat c=new Cat("加菲", "blue");
Dog d=new Dog("汪先生","red");
Lady l1=new Lady("lilian",c); //父类引用指向子类对象
l1.mypetenjoy();
Lady l2=new Lady("ranbo",d);
l2.mypetenjoy();
}
}
多态的三个条件:要有继承,要有重写,父类引用指向子类对象。
##抽象类
几个重要概念
- 抽象类
l 接口与继承的区别:继承只能单类继承,但是可以避免大量重写,接口可以多个继承,但是需要重写。另外继承和抽象不能实例化,只能通过实例化其子类来获得方法。
l 抽象类:关键字:abstract,抽象方法也是只能定义,不能实现。与接口的不同:在抽象类下可以定义普通的方法。
l 抽象类看,是一个未定义完整的类,其中抽象方法将会延迟到其子类中去实现。抽象类+子类实现的方法=完整的类
l 一个抽象类可以没有抽象方法,但这样的抽象类是没有意义的
l 一个抽象类可以有多个抽象方法。
l 抽象方法一定不能有实现。
l 一个普通类中不能含有抽象方法。
l 抽象类的子类一定要实现抽象类的抽象方法!
l 如果其抽象类的子类没有实现抽象类中的抽象方法,那么该子类也必须为抽象类。
l 接口的实现类一定要实现接口所定义的方法,同样,如果接口的实现类没有实现该接口所定义的方法,那么该实现类也必须为抽象类。
l 接口也可以继承!
l 多态的实现:1,普通类,2,抽象类,3,接口(推荐)
抽象方法相当于c++里的纯虚函数:Public abscract void enjoy();没有必要方法实现,甚至空的实现也没有必要。实现是靠子类去实现的,抽象方法就是用来被实现的。
当一个类里含有抽象方法的时候,该类必须被定义为抽象类
抽象类不能被实例化!!!!!!
抽象类就是用来被继承的!!
抽象类和接口的区别,抽象类被继承给子类的时候只能是单继承的,但是抽象类中的很多方法都可以被继承,例如构造方法,和一些非抽象的方法。接口可以被多继承,但是接口里的方法全部是抽象方法,全部需要重写,代码复用的功能被大大削弱。
##final关键字
public class TestFinal {
public static void main(String[] args) {
T t=new T();
//t.i=10; 这里会报错,因为final的成员变量不能被改变,是只读的
}
}
/*final*/ class T{ //如果这里前边有final的类,则不能被TT继承
final int i=8;
public void m(final int j){
//j=9;这里j=9报错,因为final的局部变量不能被改变,是只读的
}
public final void f(){
}
}
class TT extends T{
/*public final void f(){
}*/ //子类重写父类方法时报错,因为final的方法不能被重写。
}
##接口
接口的属性是常量
接口是一种特殊的抽象类,所有的方法都是抽象方法,不用写abstract
public class Testinterface {
public static void main(String[] args) {
Singer s1 = new Student("TML"); //引用是什么接口,那么只能访问该接口持有的方法
s1.sing();
s1.sleep();
Singer s2 = new Teacher("javateacher");
s2.sing();
s2.sleep();
Painter p1=(Painter)s2;
}
}
===================================================================
interface Singer {
public void sleep();
public void sing();
}
interface Painter {
public void paint();
public void eat();
}
====================================================================
class Student implements Singer { // 允许一个类实现多个接口,也允许多个类实现一个相同的接口
private String name;
public Student(String name) {
this.name = name;
}
public String getname() {
return name;
}
public void study() {
System.out.println("studnet study");
}
@Override
public void sleep() {
System.out.println("student sleep");
}
@Override
public void sing() {
System.out.println("student sing");
}
}
======================================================================
class Teacher implements Painter, Singer {
private String name;
public Teacher(String name) {
this.name = name;
}
@Override
public void sleep() {
System.out.println("teacher sleep");
}
@Override
public void sing() {
System.out.println("teacher sing");
}
@Override
public void paint() {
System.out.println("teacher paint");
}
@Override
public void eat() {
System.out.println("teacher eat");
}
}
程序运行结果:
student sing
student sleep
teacher sing
teacher sleep
##接口与继承
interface Protectable{
public void beprotectable();
}
interface Valuable{
int a=10;//接口里定义的都是常量,必须赋值,前面默认有public static final
public int money();
}
interface A extends Protectable{ //接口可以继承接口
public void m();
}
abstract class Animal{
public String name;
public void info(){
System.out.println("我是一种动物");
}
public abstract void enjoy();
}
class GoldenMonker extends Animal implements Protectable,Valuable,A{//类可以继承类,也可以实现接口
@Override
public int money() {
int money=10000;
return money;
}
@Override
public void beprotectable() {
System.out.println("我是一个应该被保护的猴子");
}
@Override
public void enjoy() {
System.out.println("猴子叫");
}
public GoldenMonker(String name) {
this.name=name;
}
@Override
public void m() {
System.out.println("我不是母鸡啊");
}
}
public class Testcomprehensive {
public static void main(String[] args) {
GoldenMonker gg=new GoldenMonker("monkey");
gg.info();
System.out.println(gg.a); //接口里的属性值通常来说只能被读取
gg.m();
System.out.println(gg.money());
gg.beprotectable();
Valuable v=new GoldenMonker("MONKEYMONY");//接口引用可以指向实现它的对象,但只能实现它自身的方法
System.out.println(v.money());
Protectable P=new GoldenMonker("monkeyprotect");
P.beprotectable();
}
}
我是一种动物
10
我不是母鸡啊
10000
我是一个应该被保护的猴子
10000
我是一个应该被保护的猴子
接口与抽象类的相同之处和区别
相同之处:
l 他们都可以在内部定义未实现的方法,只不过抽象类里还可以定义实现的方法。
l 他们都不可以实例化
不同之处
l 接口可以多重实现,抽象类不可以实现多个父类
l 接口只能定义未实现方法,抽象类里还可以定义实现的方法。
l 接口中基本数据类型的数据成员都默认为static和final,抽象类则不是
使用接口和抽象类的场合
发现某种东西会成为基础类,首先把其定义为接口,接口是极端的抽象类,
使用:如果创建的组建会有多个版本,则最好创建抽象类,如果创建的功能将在大范围内相异的小而简练的功能块,则使用接口。如果要设计大的功能单元则使用抽象类。
抽象类主要用于关系密切的对象(共性大于个性),而接口适合为不相关的类提供通用功能(个性大于共性)。
接口多定义对象的行为,抽象类多定义对象的属性(抽象类里不应该有太多方法)
接口不变原则,尽量增加接口而不是更改原有接口。
尽量将接口设计成功能单一的模块儿。一个接口最好只能做一件事情。
**接口与抽象类形象化比较最重要的原则:**面向接口编程。
以下是我在网上看到的几个形象比喻,真的非常不错,呵呵: 1.飞机会飞,鸟会飞,他们都继承了同一个接口“飞”;但是F22属于飞机抽象类,鸽子属于鸟抽象类。 2. 就像铁门木门都是门(抽象类),你想要个门我给不了(不能实例化),但我可以给你个具体的铁门或木门(多态);而且只能是门,你不能说它是窗(单继承);一个门可以有锁(接口)也可以有门铃(多实现)。 门(抽象类)定义了你是什么,接口(锁)规定了你能做什么(一个接口最好只能做一件事,你不能要求锁也能发出声音吧(接口污染))。
一、抽象类里面的方法可以有实现,但是接口里面的方法确是只能声明。
二、接口是设计的结果 ,抽象类是重构的结果
三、java不支持多重继承,所以继承抽象类只能继承一个,但是可以实现多个接口。
1 接口是核心,其定义了要做的事情,包含了许多的方法,但没有定义这些方法应该如何做。
2 如果许多类实现了某个接口,那么每个都要用代码实现那些方法
3 如果某一些类的实现有共通之处,则可以抽象出来一个抽象类,让抽象类实现接口的公用的代码,而那些个性化的方法则由各个子类去实现。
所以,抽象类是为了简化接口的实现,他不仅提供了公共方法的实现,让你可以快速开发,又允许你的类完全可以自己实现所有的方法,不会出现紧耦合的问题。
应用场合很简单了
1 优先定义接口
2 如果有多个接口实现有公用的部分,则使用抽象类,然后集成它。
##总结
###java的三大特性
l 封装;隐藏实现细节,对外提供公共的访问接口,增强代码的可维护性
l 继承:最大的好处就是代码复用,同时也是多态的一个前提。
l 多态:同一个接口,使用不同的实例,父类子类,抽象类,接口。都能够实现多态(一定会有个继承关系,一定会有一个重写关系,一定会有一个子类向父类赋值或者是实现类向接口赋值),以不修改原有代码的方式增加代码的功能扩展性。