继承
什么是继承
继承是OOP面向对象编程三大特点之一: 1.封装 2. 继承 3. 多态
继承是面向对象软件技术当中的一个概念,与多态、封装共为面向对象的三个基本特征。继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。
继承(英语:inheritance)。这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的属性和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
如果某类B“继承”另某类A,就把这个B称为“A的子类或派生类(subclass)”,而把类A称为“B的父类”也可以称为“A是B的超类或基类(superclass)”。
为什么使用继承?
1.提高代码的可重用性
2.起到扩展功能的作用!
需求:动物园引进新品种 Dog,模拟 id age name 属性。动物园引进新的动物 Cat.同样有 id age name 属性忽然有一天,老板说id不好 要改名 aid 。两个动物很好改,如果有一万个动物,能改很麻烦,改完运行三个月后,老板又说了,还是id好,改回来!程序员们苦逼的改改改。又改完了,运行三个月后,老板又说了,还是aid好,再改回来!。。。程序员崩溃的!如果使用继承,这个问题就迎刃而解了,我们只需要将这些共同属性放在父类中,然后让其他动物来继承,改属性名,就直接在父类改就行了......
如何实现继承
语法:
public class 子类名 extends 父类名{
}
例子:
public class Person {
//人的基本属性和行为
String name;
int age;
public Person(){
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(age+"岁的"+ name+"在吃饭。。。");
}
public void seleep(){
System.out.println(age+"岁的"+ name+"在睡觉。。。");
}
}
public class Student extends Person{//学生继承人的基本属性和行为
public static void main(String[] args) {
Person person=new Person("小木",18);
person.eat();
person.seleep();
}
}
方法的重写
听上去和方法的重载很相像,但是这两个是完全不一样的两个东西。
子类重写父类中的方法内容,重写的只是方法体的内容。
为什么出现方法的重写?
当父类的功能无法满足子类的需求时,子类可以重写父类中的方法。
Father{
smoke(){ //抽烟
sout("抽的哈德门")
}
}
Son exends Father{
//儿子也要抽烟 但是父类抽的烟无法满足子类的要求。
smoke(){
sout("抽的为中华")
}
}
Son s=new Son();
s.smoke();
重写的特点
1.子类中的方法名与父类中的方法名一致。
2.子类的方法参数要和父类的方法参数一致。
3.子类的方法的返回类型要和父类的方法的返回类型一致。
4.访问修饰符不能小于父类的。
super关键字
super表示父类对象,子类通过该对象可以调用父类被重写的方法。this表示本类对象
如果想调用父类中的方法。
父类:
public class Person {
String name;
int age;
public Person(){
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void eat(){
System.out.println(age+"岁的"+ name+"在吃饭。。。");
}
public void seleep(){
System.out.println(age+"岁的"+ name+"在睡觉。。。");
}
public void introduced(){
System.out.println("年龄:"+age+"\n名字:"+name);
}
}
子类:
public class Student extends Person{
public void introduced(){
super.introduced();//调用父类内容
System.out.println("是一名学生");//在父类方法的基础上加以补充....
}
}
测试类
public class Test {
public static void main(String[] args) {
Student student=new Student();
student.age=18;
student.name="小木";
student.introduced();
}
}
创建子类对象时构造方法的加载顺序
再调用子类对象的构造方法时,先执行父类的构造方法,再执行子类的构造方法。【先有爹再有儿子】
public class Test01 {
public static void main(String[] args) {
S s=new S();//调用对应类的构造方法
}
}
class F{
//表示父类的构造函数
public F(int a){
System.out.println("父类无参构造函数");
}
}
class S extends F{
public S(){
super(15);//默认省略super()表示调用父类的无参构造方法,而且这句话必须放在子类构造方法的第一行代码;
//如果父类中没有定义无参构造函数,则子类构造方法会出现错误。 必须手动调用父类有参的构造函数
System.out.println("儿子的构造函数");
}
}
验证: 再初始化子类时,先初始化父类对象,再初始化子类对象。
案例:
public class Test {
static {
System.out.println("1. Test的静态代码");
}
public static void main(String[] args) {
Son son = new Son();
System.out.println("6.主函数代码");
Son son1 = new Son();
}
}
class Father{
public Father(){
System.out.println("2.父类的构造方法");
}
static{
System.out.println("3.父类的静态代码块");
}
}
class Son extends Father{
static {
System.out.println("4.子类的静态代码块");
}
public Son(){
System.out.println("5. 子类的构造方法");
}
}
//1. 静态代码块--会随着类的加载而被加载而且只会被加载一次。
//2. 先在家父类得到构造方法再加载子类的构造方法。
//13425625.
零散的内容
java中只允许单继承。----一个类只能继承一个父类。
java允许多层继承。----->A extends B{} B extends C{}
final关键字
意思: 最终的。它可以修饰属性,方法,修饰类。
final如果修饰属性表示该属性为常量,其值不能改变,而且必须赋值。
final修饰方法表示该方法为最终方法,不允许子类重写该方法。
final修饰类表示该类为最终类,不允许子类继承。
public class Test01 {
public static void main(String[] args) {
Teacher t=new Teacher();
t.show();
t.print();
}
}//final修饰的类表示最终类,不能被子类继承。
final class People{
public int age; //普通成员变量
public final String name="刘德华"; //final修饰的属性为常量,必须赋值。而且该值不能改变
public void show(){
// name="张学友";//而且该值不能改变
age=55; }
//final修饰了该方法,表示该方法不能被重写。
public final void print(){
System.out.println("~~~~~~~~~~~~~");
}
}
class Teacher extends People{
//
public void print(){
//子类无法重写父类中使用final修饰的方法,但是它可以被子类继承。
//// }}
例如String类能否被其他类继承呢? 不能。
String类的内容不能改变--每次修改都会创建新的对象--而且指针指向新的对象。private final char value[];
因为String存放的字符串都放在一个字符数组中,而字符数组使用final修饰。
访问修饰符
类成员使用不同的访问修饰符,导致类中成员的访问范围不同。
public:公共的。表示当前工程下任意类都可以访问该修饰符修饰的成员。
protected: 保护的。 表示只允许当前类的子类以及当前类所在包的类访问。
default:默认。表示只允许同一个包下的类访问。
private:私有 表示只允许同一个类下的成员方法。
Object类
表示所有类的根类,直接或间接的继承了Object类。如果某个类没有显示的继承父类,则默认继承了Object类。
class Food extends Object {
//没有显示的继承任何类,默认继承了Object类
}
toString()方法
当打印一个类对象时,默认调用的就是toString方法。
思考: String类对象为什么打印时不是刚才地址效果。 而是打印的为字符串的内容。
原因: String类重写了Object中toString方法了。我们后期也可以定义类时重写toString方法。打印我们自己类的信息。。
package demo03;
import demo02.Animal;
public class Test {
public static void main(String[] args) {
Food f=new Food("红烧肉",25);
System.out.println(f);
System.out.println(f);//发现直接打印对象和通过对象调用toString效果一样
}
}
class Food extends Object { //没有显示的继承任何类,默认继承了Object类
private String name;
private double price;
public Food() {
}
public Food(String name, double price) {
this.name = name;
this.price = price;
}
//重写Object类中的toString方法
@Override
public String toString() {
return "食物名:"+name+";价格:"+price;
}
}
equals方法
可以比较两个对象的内容是否相同。默认比较的是两个对象的地址是否一致。
因为String类重写了equals方法,让其变为值的比较。 后期如果你想比较自己自定义类的对象的内容,也可以重写equals方法。
包装类
万事万物皆为对象。 我们的基本类型就不是对象。我们就为基本类型包装了对应的包装类,这些类可以操作基本类型的数据。
byte---->Byte类[操作byte数据类型 该类中封装很多方法]
short--->Short类
int----->Integer
long---->Long类
float--->Float
double---->Double
boolean---->Boolean
char------>Character
自动装箱
装箱: 把基本类转换为对应的包装类型。这个过程叫装箱。
自动装箱: 把基本类型自动转换为包装类型。
public class Test01 {
public static void main(String[] args) {
int a=10;//基本类型
Integer b=a; //基本类型自动转为了包装类型--自动装箱。jdk1.5后出现。
Integer c=new Integer(a);//手动把基本类型封装到包装类上。
}
}
自动拆箱
拆箱: 把包装类型转换为对应的基本类型。这个过程叫拆箱。
public class Test01 {
public static void main(String[] args) {
int a=10;//基本类型
Integer b=a; //基本类型自动转为了包装类型--自动装箱。jdk1.5后出现。
Integer c=new Integer(a);//手动把基本类型封装到包装类上。
int d=b; //把包装类型自动转换为基本类型--自动拆箱。jdk
}
}
** 如何把一个字符串数字转换为整数。**
public class Test02 {
public static void main(String[] args) {
String str="123";
//把上面的字符串转为为数字类型。
int a=Integer.parseInt(str);
int compare = Integer.compare(2, -2);//比较两个整数是否相同 如果相同返回0 否则返回为0
System.out.println(compare);
}
}