最近学了一波Java,在学习Java过程中有下列问题值得研究,同时我还与C++进行了比较,首先在学习过程中有下面几个问题:
1.为什么需要继承?如何继承?继承到什么?
2.方法的重载与重写的区别
3.类型的自动转换和强制转换
4.子类特有的方法的调用规则
5.子类重写的方法的调用规则
6.多态的理解
7.面向对象的三大特征
8.继承中的super和this
我们一一解答这些问题。
1.为什么需要继承?如何继承?继承到什么?
答:为什么需要继承?
(1)为了体现现实中类之间的关系
(2)减少代码冗余
(3)对父类实现修改和扩展
这一点C++与Java感觉没什么区别,继承就是为了完成以上3点。
如何继承?
C++中继承语法:class 派生类名:基类名表{
数据成员和成员函数声明
};
其中基类名表构成:访问控制 基类名1,访问控制基类名2.....
访问控制表示派生类对基类的继承方式,使用关键字:
public: 公有继承 父类成员在子类中保持原有的访问级别
private: 私用继承 父类成员在子类中变为private成员
protected: 保护继承 父类public成员会变成protected
父类protected成员仍然为protected
父类中private成员仍然为private
注意:private成员在子类中仍然存在,但是却无法访问到。不论以何种方式继承,派生类都不能直接使用基类的私有成员。
例题:
/*创建一个车类,有品牌、速度,能跑。
有客车,货车都继承于汽车类
客车可以载客,多一个载客量属性。
货车可以运货,多一个吨位属性。
客车和货车都重写跑函数。*/
#include <iostream>
using namespace std;
class Car
{
public:
virtual void run() = 0;
char* name;
private:
};
class keche:public Car
{
public:
keche(char* name,double speed)
{
this->name = name;
this->speed = speed;
}
void run()
{
cout << name<< "的速度为:" << speed << endl;
}
private:
double speed;
};
class huoche :public Car
{
public:
huoche(char* name, double speed)
{
this->name = name;
this->speed = speed;
}
void run()
{
cout << name<< "的速度为:" << speed << endl;
}
private:
double speed;
};
void print(Car *base)
{
base->run();
}
int main()
{
keche keche1("奥迪", 150);
huoche huoche1("解放",80);
keche1.run();
huoche1.run();
return 0;
}
Java中继承语法:public class B extends A{} 使用extends进行继承
例题:
public class Auto{
private int tyres;
private String color;
private float weight;
protected float speed;
public Auto(){
}
public Auto(int t){
tyres=t;
}
public Auto(int t,String c){
tyres=t;
color=c;
}
public void jiasu(){
speed++;
System.out.println("汽车在加速,速度为:"+speed);
}
public void jiansu(){
speed--;
System.out.println("汽车在减速,速度为:"+speed);
}
public void tingche(){
speed=0;
System.out.println("汽车停下来了,速度为:"+speed);
}
}
public class Car extends Auto{
private String kongtiao;
private String cd;
public void jiasu(){
speed+=5;
System.out.println("小汽车在加速很快,速度为:"+speed);
}
public void jiansu(){
speed-=5;
System.out.println("小汽车在减速很快,速度为:"+speed);
}
}
继承到什么?
C++中派生类对象存储了基类的数据成员,派生类可以使用基类的方法。注意派生类是没有继承构造函数的,也就是派生类需要自己的构造函数,派生类可以根据需要添加额外的数据成员和成员函数。
Java中1.继承到了可访问的属性和方法,子类可以定义自己特有的属性和方法【必须是子类类型的对象才能调用】,子类可以重写[覆盖]从父类继承来的属性和方法【根据对象new的是什么类型,就调用那个类中的方法】
扩展:
(1)Java中的继承是单根继承,一个类有且只有一个父类 所有类都默认继承object类的。
(2)C++中可以多继承,例如一个派生类可以继承两个父类,使它拥有两个父类都有的函数和属性。
(3)Java没有指针,C++因为是兼容c语言的,所以C++中是用指针的。
(4)Java中创建一个对象的时候只用一种方法 Student s=new Student(参数);
C++中有多中形式:Student s=new Student; Student s=new Student();Student s=new Student(参数);
(5)Java中对父类的构造函数的使用是在子类中加一个super(参数)
public class Student extends Person{
public Student(){
//super() 指的是父类的无参构造方法
//在子类的构造方法中默认调用父类无参的构造方法
//super();
super("张三");
System.out.println("Student");
}
public void eat(){
System.out.println("大学生在吃饭");
}
}
C++中是使用参数列表来实现的
子类构造对象的时候需要调用父类的构造函数来对继承过来的成员进行初始化。
class A{
public:
A(int a,int b,int c):father(a,b)
{
this->c=c;
}
private:
int c;
};
(6)Java中没有析构函数
C++中有析构函数,语法格式为:~类名
特别的是:在子类对象析构的时候,需要调用父类的析构函数对继承来的成员进行清理。
2.方法的重载与重写的区别
答:这个感觉内容差不多,但是实现的方式不同。
Java中:
方法的重写:在子类中修改从父类中继承来的方法
方法名,参数列表,返回值都必须一样
访问限定符不能缩小
方法的重载:在同一个类中,有多个同名不同参数列表的方法
重载和方法的访问限定符,返回值没有关系
c++中:
函数重载:
必须在同一个类中进行
子类无法重载父类的函数,父类的同名函数将被覆盖。
重载是在编译期间根据参数的类型和个数决定函数调用。
函数重写:
必须发生于父类和子类之间
并且父类和子类中的函数必须有完全相同的原型
使用virtual声明之后能够产生多态(如果不使用virtual,那叫重定义)多态是在运行期间根据具体对象类型决定函数调用
为什么使用virtual关键字会产生多态,请看我写的http://blog.csdn.net/sum_tw/article/details/52976324 C++vptr指针的存在。
不加virtual是静态联编,关于静态联编我会在以后的博客中介绍。
3.类型的自动转换和强制转换
Java中的转换问题
//类型向上自动转换:子类对象的类型可以自动转成父类类型
//Student为父类 UNStudent为子类
Student stu3 = new UNStudent();
stu3.setName("王五");
//stu3.study();
//类型向下强制转换:将父类类型的对象强制转换成子类类型
//可能出现逻辑错误
UNStudent stu4 = (UNStudent)stu3;
//stu4.study();
C++中的转化问题感觉跟Java差不多,但是要注意C++可是有指针的
看一个例子:(不考虑多态的情况下)
void print1(Parent *base){
base.print();
}//指针
void print1(Parent base){
base.print();
}//对象
这个时候不管你后面传什么类型的指针,都只会调用父类的方法。
4.子类特有的方法的调用规则
在Java中:
public class Student{
protected String name;
public void setName(String s){
name = s;
}
public class UNStudent extends Student{
//子类特有的方法
public void cet4(){
System.out.println(name+"是大学生,要考四级");
}
}
这里要注意,study(String km)是重载子类中的study();
public class Demo{
public static void main(String[] args){
UNStudnet stu=new UNStudent();
stu.cet4();
}
}
C++中也是类似的,这里就不剧举例了。
5.子类重写的方法的调用规则
Java中:
//学生类
public class Student{
protected String name;
public void setName(String s){
name = s;
}
public void study(){
System.out.println(name+"在学习");
}
}
//大学生,继承学生类
public class UNStudent extends Student{
//子类特有的方法
public void cet4(){
System.out.println(name+"是大学生,要考四级");
}
//子类重写从父类中继承来的方法
public void study(){
System.out.println(name+"是大学生,学习是为了工作");
}
protected void study(String km){
System.out.println(name+"是大学生,学习是为了工作"+km);
}
}
public class Demo{
public static void main(String[] args){
Studnet stu=new UNStudent();
stu.cet4();//调用自己的方法
stu.study();//发生多态
stu.study("aaa");//重载自己的方法
}
}
6.多态的理解
Java中的多态
多态:相同类型的对象,调用相同的方法,得到的结果可能不一样
静态多态:方法的重载导致的
动态多态: 方法的重写导致的
C++中的多态:
三个条件:有继承,有virtual重写,有父类指针指(引用)向子类对象。
C++的多态实现离不开vptr指针,离不开动态联编,这些在以后的博客中详细讲。
7.面向对象的三大特征
特征:继承 多态 封装
封装:也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
继承:继承是指这样一种能力,它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。一般情况下一个子类只能继承一个基类。
多态:相同类型的对象,调用相同的方法,实现不同的状态。
实现多态有两种方式:覆盖(动态多态),重载(静态多态)。
它们各自的作用?
封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了代码重用。而多态则是为了实现另一个目的接口重用。多态的作用就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。
8。继承中的this和super
this:构造方法中的this表示当前正在初始化的对象引用,方法中的this表示当前正在调用此方法的对象引用。this具体用法表现在一下几个方面:
1.当有多个重载的构造方法时,且一个构造方法需要调用另外一个构造方法,在其第一行使用this形式调用,且只能在第一行;
2.当对象中一个方法需要调用本对象中其他方法时,使用this作为主调,也可以不写,实际上默认就是this作为主调;
3.当对象属性和方法中的局部变量名称相同时,在该方法中需要显式的使用this作为主调,以表示对象的属性,若不存在此问题,可以不显式的写this。
super:表示调用父类中相应的属性和方法。在方法中,若需要调用父类的方法时,也一定要写在第一行。在Java中,super关键字有两个主要用途
第一种用途是:在子类的构造方法中,super关键字可以显式地调用父类的构造方法,用于将参数传递给它;其一般语法是:super(实际参数);
需要注意的是:该语句必须是子类构造方法的第一条语句。
第二种用途是:如果父类和子类中有同名成员,在子类中默认访问是属于自己的那一个成员;
super关键字可以明确地指定要访问父类中的成员;其一般语法是:super.成员名;
前提条件是:父类中的该成员不是private的。这两种用途都和父类有关。