标签:ima j2se 定义 etc 维数 重写 好处 出现 访问
在Java中继承的 关键字是 extends 代表一个类继承另一个类.
继承的含义以及作用: 继承就是基于某个父类的扩展.制定出来的一个新的子类.子类可以继承父类原有的属性跟方法. 也可以自己增加特有的属性跟方法.
代码例如下:
public class Anmail { public void eat() { System.out.println("父类吃"); } }
父类代码
子类代码:
public class Dog extends Anmail { public void eat() { System.out.println("子类吃"); } }
通过上面代码.我们可以看到.子类 Dog类. 继承了父类. 使用了关键字 extends
并且子类重写了父类的方法.
上面说了子类继承父类.那么子类也可以调用父类的方法. 我们学过this关键字. this可以区分局部变量跟成员变量.也可以在构造中调用其它构造函数.
那么我们还提供了一个关键字. super() super关键字可以访问父类.
代码如下:
父类代码一样.之帖子类代码.
public class Dog extends Anmail { public Dog() { super(); //调用父类构造 调用构造的时候必须放在最上面. super.eat();//调用父类方法. } public void eat() { System.out.println("子类吃"); } }
创建子类对象.并且输出.
可以看到.在调用构造的时候.他会先访问父类的构造.但因为父类构造我们并没有输出内容.所以没有输出内容,子类继续调用父类的eat方法. eat方法我们输出了.
就是父类吃. 所以在子类构造的时候.会调用父类构造以及父类的方法.
super()的关键字用法限制. super关键字只能调用父类中 公共权限(public) 以及保护全选(protected)的方法
子类可以重写父类的方法. 什么是重写.就是子类跟父类的方法是一模一样的. 也就是说,重写是在子类跟父类中才会出现的. 返回值一样. 方法名一样. 参数一样.
在J2SE 5.0 以上.支持了新的功能.也就是说返回值可以不一样.但是 方法名 跟 参数必须一样.
JAVA 类编译的流程. java中.创建子类的时候.会自动调用父类的构造方法进行初始化. 我们可以做个例子. 并且重写一个方法.
public class Anmail { public Anmail() { System.out.println("父类构造方法"); } public void eat() { System.out.println("父类吃"); } }
子类.
public class Dog extends Anmail { public Dog() { } public void eat() { //重写父类方法 System.out.println("子类吃"); } }
创建对象.
通过实例可以终结出. 1. 子类重写了父类方法.输出的内容是自己的"子类吃" 2.在给子类实例化的时候.会自动调用父类进行实例化操作.也就是说父类也会被初始化.
PS: 子类实例化的时候.会调用父类的无参构造进行实例化父类.但是并不会自动调用父类的有参构造.这个我们需要使用super关键字才可以.
object类是一个比较特殊类的. 位于java.lang.包中. 它是所有类的父类.比如我们以前学习过字符串类. String类. String类中 我们比较两个对象是否相等就是用.
equleas()方法. 这个就是object类中的.只不过字符串进行了重写. 我们自定义的类也是继承自object类.只不过是默认继承. 所以任何类都可以重写父类object中的方法.
在object类中 加了final类的方法是不能被重写的. 例如 getClass() notify() notifyAll() wait()等等.
1.getClass()方法
getClass()方法会返回指定是的Class实例. 然后可以使用此时调用getName()获得这个类的名称.
getClass().getName(); 也可以配合toString()方法使用.
2.toString()方法
toString()方法就是返回一串字符串.在object类中,就是讲一个对象返回为字符串形式.实际应用中就是重写这个字符串.返回什么是你自定的.
3.equals()方法;
equals()方法就是比较.当时说过区别. 就是 == 与 equals()的区别. == 是比较地址. equals()是比较你自定的内容.也就是对象的实际内容.通常也是重写.
比较什么你自己定. 如果你写了一个类有一个成员变量是 a; 我们重写equals() 就判断 a 跟 比较对象的a即可. 就是 a 跟 a比较.
对象类型转换.包括向上转型.以及向下转型. 通俗理解就是 强转对应的数据类型. 但是你在强转的时候要判断一下是否是这个数据类型.这个就是转型.
向上转型以及向下转型就是说 类我们强转为父类. 也可以父类强转为子类.
子类对象赋值给父类对象称为向上转型. Anmail a = new Dog(): 这个就是向上转型.
比如我们有动物对象. 跟 狗对象. 狗对象可以看做是动物对象的一个子类.
还比如 四边形类 跟 平行四边形类. 平行四边形 对象可以看做是 四边形类的一个对象.
如下图:
常规的继承图都是父类在上. 子类在下.例如上图. 所以我们将子类看做是父类对象的时候成为向上转型. 也就是平行四边形对象看做是四边形类的对象的时候.
向上转型是具体的类像抽象的类进行的转换.所以它总是安全的. 我们可以说平行四边形是特殊的四边形. 但是不能是四边形是平行四变形.
因为代码写法: 四边形 a = new 平行四变形(); 所以很多人就会说 a就是平行四边形. 其实是错的. a是四边形. 我们只能说a平行四边形是一个特殊的四边形.
如果在C++ 中.内存分配就是 父类占一小块内存. 子类上半部分是父类内存.下半部分是子类特有的成员变量开辟的内存. 子类转为父类. 就是不要子类下边的内存了.
所以总是安全的. 我只要上面的哪块内存.也就是父类的内存.
所以在上边. 子类转为父类. 父类调用方法的时候.并不会调用到子类特有成员变量.
向下转型就是 抽象的类转为具体的类. 比如 动物是鸟. 动物是抽象的.不能说他是鸟.所以不和逻辑.而且会出现问题.
比如父类 Anmail a = new Dog();
Dog b = a; 这样是错误的. 我们不能这样赋值.原因就是不能说 动物是狗.
Dog c = (Dog)a; 这样可以.强转为子类型.写法是正确的.
站在C++的角度:
为什么上面向下转型是错误的. 原因是 a 会有一块内存. 我们可以假定为0x20个字节大小. b是Dog也就是子类对象.他继承了父类.有自己特有的成员方法
以及成员变量. 所以它的头0x20个字节是父类的内存.下面多出的内存是自己了.假设是0x30个字节. 所以我们子类转为父类(向上转型)
其实就是把30个字节的内存转为20个字节的内存.所以不会出问题. 但是 0x20个字节.也就是父类转为子类. 就会出为题. 意思就是说 0x20个字节转为0x30个字节.
首先我们并不知道是转为0x30个字节.这样内存访问就会出错了.但是如果我们强转了.相当于就是父类在强转为子类的时候.按照子类的内存强转.这样就不会有问题了.
也就是上面的我们的 Dog c c的头0x20个字节是父类. 下面的0x10个字节就是自己特有的所以不会出错.
上面我们的父类转为子类的时候.必须加上子类的数据类型才可以强转. 原因就是转为子类的时候.内存会按照子类的大小进行扩大.这样就不会出现问题了.
但是我们怎么知道 我们的子类.是否是这个父类的子类. 所以有了运算符 instanceof()来判断.
就是判断 子类是否是父类的. 父类中有没有这个子类.如果有就进行转换.
语法:
Myobject instance ExampleClass
1.Myobject 就是某个类的对象引用. 可以理解为是父类填写的是父类引用.
2.ExampleClass 某各类. 可以理解为子类. 填写类名.
例如:
Anmail a = new Anmail(); if (a instanceof Dog) { 判断父类中是否有子类Dog,如果有我就进行转换. Dog d = (Dog) a; d.xxxx; }
重载的含义. 重载就是可以有多个相同函数.重载的参数确定是否重载.
我们写过有参构造跟无参构造. 方法名是一样.不一样的就是参数列表不同.
重载的构成:
1.重载的构成是方法名字一样,
2. 参数列表个数不同
3. 参数类型不同
4.参数列表顺序不同
例如:
public void eat();
public void eat(String,int); 重载eat,参数是String,int
public void eat(int,String); 参数顺序不同.构成重载.
public int eat(int,int); 返回值是int. 参数列表是两个int值. 返回值也可以为void不影响重载.
PS: 方法的返回值并不会影响重载.真正影响的是参数列表. 你有两个成员方法.方法命一样.参数列表一样.类型一样.返回值不同.不能构成重载.
特殊的重载:
Java中可以定义不定长的参数类表.
语法如下:
返回值 方法名(参数数据类型 . . . 参数名称) 主要是三个...
其实不定长参数.就是一个一维数组.我们可以当做数组去操作参数.
代码如下:
public void eat(int ... a) { for (int i = 0; i < a.length;i++) { ....... } }
在上面我们学过向上转型.就是子类对象可以当做父类对象去使用. 其意思就是我可以当做父类对象去使用. 那么就可以使用子类跟父类的共有的方法跟属性了.
因为我们站在内存的角度上也说了.我们用的都是父类的内存.所以我们可以调用父类的方法.跟成员去使用. 但是多态是什么意思.多态就是调用父类的方法的时候.
因为子类重写了父类的方法.所以调用时会调用子类的特有方法.
例如:
Anmail a = new Dog();
a.eat()
输出结果: 子类吃. 按理说应该输出父类吃.不是说向上转型了.我们用的都是父类内存了.子类就不该会被调用. 愿意你是这样了.如果站在C++角度来说.
我们首先会new一个子类的对象实例. 而new子类对象的时候.会先初始化父类. 在初始化自己. 为什么说一下流程.原因是父类有虚表.也就是有一个表.保存着
自己的方法.而子类在实例化的时候.父类的虚表先初始化. 初始化完了之后.子类的再初始化.它会先把父类的虚表拷贝过来.然后覆盖他. 这样我们a调用方法的时候
其实调用的是子类方法.原因就是子类的虚表已经覆盖了父类虚表.
Java中的原理. java中其实也是一样的.只不过给你隐藏了这个步骤了.不用理解的这么复杂.我们只要知道.向上转型之后.调用子类跟父类共有的方法.就能实现多态.
注意: 子类重写了父类方法.那么调用的时候才是子类的方法.原因是子类重写了.才会覆盖父类.
代码例子:
多态的用法: 多态的好处就是程序员不同定义相同的方法了.避免了相同的大量重复代码的开发.只要实例化一个子类对象.维护这个方法即可.
再举个例子;
我们手机. 有一代手机 二代手机 三代手机 四代手机 ...n代手机.
1代手机 只支持打电话
2代手机 可以发信息了.
3.手机 可以上网了
4.手机 可以拍照了.
此时我们只需要二代手机继承1代手机对1代手机扩展功能. 比如增加发信息的方法. 打电话的方法进行重写.可以打电话.也可以录音了. 而一代手机根本不用动方法.
此时我们的二代手机就可以出手了.第三代手机同样继承第二代手机.增加扩展功能.重写维护的方法. 而不用修改二代的代码.
这样不管我们有第几代手机.只需要继承上一代的类.进行扩展.以及维护即可.
抽象类就是说一个不可以被存在的类. 比如我们有动物 跟 狗. 而动物是不能被实例化对象的. 狗是一个具体的生物.我们可以实例化.
所以抽象就是指 动物. 也就是说我不能让你被实例化.原因就是 动物泛指万千.不能具体为一个动物.
定义抽象类的关键字
abstract
使用abstract 修饰的类称为抽象类.是不能实例化的.
使用 abstract 修饰的方法.称为抽象方法.是不能实现的.比如子类重写. 修饰的方法没有方法体.
反过来说.如果一个类中修饰了成员方法.那么就必须定义这个类为抽象类.
抽象类跟普通类一样.只不过就是不能实例化. 必须要有子类继承.如果有抽象方法.子类必须重写.
抽象类的继承图:
代码写法,需要将我们的Anmail类写成抽象类. 并且方法改为抽象方法
//public abstract class Anmail abstract public class Anmail { abstract public void eat() ; public abstract void play(); }
abstract 卸载权限修饰符的前边或者后边都可以.不影响.例如类上面加了一行注释.我们也可以写成上面的写法.以及抽象方法.也是两个不同顺序来举例子
public class Dog extends Anmail { @Override public void eat() { // TODO 自动生成的方法存根 System.out.println("狗在吃东西"); } @Override public void play() { // TODO 自动生成的方法存根 System.out.println("狗在玩耍"); } }
使用的时候.可以使用向上转型.使用多态的方式. 子类可以自己new自己
在C++中.也有抽象类的概念.只不过称之为纯虚类. 他的方式就是这个类中的方法定义为纯虚方法(抽象方法)
void eat() = 0; 后面加上 = 0; 跟接口很类似. 一般也是接口
接口就是抽象类的延伸.上面我们定义了一个抽象类.如果这个抽象类是一个父类.有很多子类.但是我们可以这样想一下. 如果子类很多.都要实现这个抽象类中的方法.
这样就造成了代码冗余. 我们有的类完全可以不实现抽象类中的抽象方法啊.
比如 play方法. 我们每个子类都要实现.但是有的动物就不会玩我完全可以不实现了.但是按照抽象类.我们必须实现.所以就代码冗余了.
此时接口就出现了. 接口就是说 . 我接口中的方法都是抽象方法. 你要实现play. 就可以实现我这个接口. 如果不需要玩的话.就不用实现我这个接口
例如下图:
可以看到我们的N边型类.并没有实现接口.我完全可以不用实现Draw方法.虽然我继承了父类.
接口的定义与使用:
1.接口使用intface关键字 修饰. 可以使用权限修饰符修饰
2.接口的实现使用关键字 implements关键字
3.接口中的方法都是抽象方法.而且都没有方法体. 且默认加的关键字就是abstract 而且权限必须是public因为要被实现.其它权限修饰则不被编译器认可.
4.在继承一个类同时.可以实现接口.
5.在接口中定义的 字段(成员变量)都是默认修饰符 static + final修饰的. 也就是说一个静态常量.
代码如下:
定义一个接口
public interface IAnmail { public abstract void Play(); //定义一个抽象方法 }
接口的实现.
public class Dog extends Anmail implements IAnmail{ @Override public void eat() { // TODO 自动生成的方法存根 System.out.println("狗在吃东西"); } @Override public void Play() { //实现了接口必须实现他的方法 // TODO 自动生成的方法存根 System.out.println("狗在玩耍"); } }
类的继承使用 extends关键字
注意的问题:
1.不能多继承.
2.子类继承父类自动用于父类的方法以及成员变量
3.子类在构造中可以调用父类构造.(无参或者有参) 使用的是 super();关键字. 也可以调用父类方法 super.xxxx
在Java中每个类都继承了父类Object. Object中提供了常用的方法
比较: equeals();
转为字符串表现形式 toString();
这些方法都是可以被重写的.除了加了 final修饰的.
在Java中有向上转型跟向下转型
1.向上转型: 子类转为父类. Anmail d = new Dog(): 安全的.因为在内存角度来说.使用的部分只有父类部分内存.
2.向下转型: 父类转为子类 Dog c = (Dog) d; 必须加上类型.父类内存转成子类内存,比如给指定子类内存大小.
3.对象类型判断 使用 instanceof
语法 父类引用 instance 子类类名 判断父类是否有这个子类
如果是我们就可以进行转换了.
重写:
1.返回值相同
2.方法名相同
3.参数列表相同
满足以上三点才能是重写.也就是子类跟父类一模一样才是重写.
重载:
1.方法名一样
2.参数列表个数不同
3.参数列表类型不同
4.参数列表顺序不同.
满足以上四点才能构成重载.
特殊重载可以使用 三个点定义为可变参数 public void eat(int ...a); 此时a就是一个数组.我们可以遍历他来获取参数.
多态就是父类可以调用子类跟父类共有的方法.比如是子类重写父类才会有不同的结果.
使用向上转型
Anmai a = new Dog(); a.eat() ; 狗在吃东西.
内存角度来说. 就是虚表覆盖.
抽象类使用 abstract关键字进行修饰
public abstract class 类名{}‘
1.修饰类就是抽象类,不可以被实例化.就是不能创建对象
2.修饰方法就是抽象方法,没有方法体.子类继承比如重写.
3.一个类中有抽象方法.则这个类必须定义为抽象类.
接口定义的关键字 Intface public intfact 接口名{}
实现接口的关键字 implements public class Anmail Implements 接口名
1.接口中的方法都是抽象方法. 且默认修饰符为 public abstract 权限必须是public 否则编译器不认可.
2.接口中的成员变量都是默认的 static final 修饰的.
标签:ima j2se 定义 etc 维数 重写 好处 出现 访问
原文地址:https://www.cnblogs.com/iBinary/p/9792055.html