21.构造方法(续):
分类:
隐式构造方法:如果在一个类中,没有手动编写构造方法,则系统会提供一个默认的无参的构造方法
显式构造方法:如果在一个类中,手动编写构造方法,则系统不会提供默认的无参的构造方法
建议:当手动编写构造方法时,建议先编写无参构造方法
22.引用数据类型
String
用户自定义类型,如:Teacher、Student
注意:引用数据类型赋值两种方式:赋值对象,赋值为null
小知识点:当一个对象作为另一个对象的属性
或者当一个对象中的属性是引用数据类型
23.空指针异常
java.lang.NullPointerException
出现空指针异常原因:说明该引用名称中存放的不是某个对象的地址,也就是null
解决办法:在调用某个对象中的属性或方法之前,必须保证该引用名称存放的是对象的地址
24.封装
24.1面向对象三大特征:封装、继承、多态
24.2封装
隐藏类的内部信息,不允许外部程序直接访问,而是通过方法进行操作
24.3封装的操作步骤:
第一步:将属性设置为私有的private,只能在本类中使用
private int age;
第二步:设置属性的get取值和set赋值方法
//赋值方法
public void setAge(int age){
//第三步:适当位置编写判断语句
if(age >= 0 && age <= 120){
this.age = age;
}else{
this.age = 21;
}
}
//取值方法
public int getAge(){
return age;
}
* 编写人Person类,属性:名字、年龄、性别,通过封装完成对属性赋值和取值 */ class Person{ //属性 private String name; private int age; private char sex; //编写所有属性的赋值方法 public void setName(String name){ this.name = name; } public void setAge(int age){ //当年龄在0---120为合法的,否则为21 if(age >= 0 && age <= 120){ this.age = age; }else{ this.age = 21; } } public void setSex(char sex){ //性别只能是男或女,否则性别为女 if(sex == '男' || sex == '女'){ this.sex = sex; }else{ this.sex = '女'; } } //编写所有属性的取值方法 public String getName(){ return name; } public int getAge(){ return age; } public char getSex(){ return sex; } } //编写人的测试类 class PersonTest{ public static void main(String[] args){ //实例化Person Person p = new Person(); p.setName("李四"); p.setAge(23); p.setSex('n'); System.out.println("姓名:" + p.getName() + " 年龄:" + p.getAge() + " 性别:" + p.getSex()); } }
25.this关键字
this代表当前这个对象,也就是说当前谁调用该方法则this代表就是谁
this关键字可以访问当前类中的属性、方法、也可以访问构造方法
注意:
1.当访问本类中的非静态方法和属性时,默认前面添加this.
2.当访问本类中的构造方法时,必须编写在构造方法中,并且是第一条语句
3.构造方法不能出现递归调用
26.参数传递
26.1基本数据类型作为参数传递----传递值
总结:当基本数据类型作为参数进行传递时,传递的是值,当有一个方法中的值发生改变,则对另一个方法中的值没有任何影响(各自是独立的)
26.2引用数据类型作为参数传递----传递地址
总结:当引用数据类型作为参数传递时,传递的是地址,当一个方法中属性的值发生改变时,对另一个方法中的属性值有影响(共用同一个地址)
27.static关键字
27.1 static关键字可以修饰属性
---该属性在方法区中开辟空间
---访问时可以使用类名.属性名称、引用名称.属性名称,当引用名称的值为null时也可以访问
如:Student.address
stu.address
stu = null;
stu.address
---与类同生死,生命周期长
---类优先于对象
27.2好处:节省空间
27.3.3static关键字可以修饰方法
注意:
1.静态方法中只能访问静态属性和方法
2.实例方法中可以访问静态的属性和方法,也可以访问实例属性和方法
3.3static关键字可以修饰代码块 ,称为静态代码块
static{
}
作用:完成静态属性赋值的
注意:1.当类被第一次载入时,静态代码块就自动执行
建议:当调用静态属性或静态方法时,使用类名
练习:
编写一个狗类,属性:名字、颜色、年龄、品种,方法:输出信息
编写一个猫类,属性:名字、颜色、年龄,方法:输出信息
编写测试类,分别创建猫和狗的对象,输出信息
分析:发现以上猫类和狗类中有相同的属性、方法,能否将共有的属性和方法编写一次?
-----能
解决办法:
1.将相同的属性和方法编写在单独的一个类中,称为父类
2.然后在猫和狗子类中继承父类,并编写子类中独有的属性和独有的方法
动物Animal类:
共有属性:名字、颜色、年龄
共有方法:输出信息
狗类 继承 动物类
独有属性:品种strain
猫类 继承 动物类
/第一步:编写父类Animal class Animal{ //属性也叫做成员变量或实例变量 String name; String color; int age; //方法也叫做成员方法或实例方法 public void show(){ System.out.println("名字:" + name); System.out.println("颜色: " + color); System.out.println("年龄:" + age); } } //编写狗的子类并继承父类Animal class Dog extends Animal{ //编写独有的属性 String strain; //编写show方法,输出狗的所有信息-----方法的重写 public void show(){ System.out.println("名字:" + name); System.out.println("颜色: " + color); System.out.println("年龄:" + age); System.out.println("品种:" + strain); } } //编写猫的子类并继承父类Animal class Cat extends Animal{ } //编写测试类 class Test{ public static void main(String[] args){ //创建狗的对象,输出信息 Dog dog = new Dog(); dog.show(); //调用子类中重写后的show方法 System.out.println(); //创建猫的对象,输出信息 Cat cat = new Cat(); cat.show(); //调用父类中的show方法 } }
28.继承
28.1好处:减少代码的冗余性
28.2面向对象有三大特征:封装,继承,多态
28.3继承画类图
28.4编写继承的代码
第一步:编写父类
第二步:编写子类
class 子类名称 extends 父类名称{
}
注意:在Java中,所有类都是从Object类继承过来的,也就是说所有类的根都是Object
class Dog{
}
//等价于
class Dog extends Object{
}
也就是说如果父类是Object则可以省略不写
28.5 方法重写(override)也叫覆盖
在子类中重写父类中的方法,必须保证子类中方法的名字与父类方法名称一致、参数列表一致、返回一致或父类方法返回类型的子类类型、修饰符不能缩小范围
注意:
1.只能重写父类的实例方法
2.私有的方法不能被重写
2.继承的注意事项
---当子类继承父类时,继承父类中属性和方法,但是父类中的私有成员(成员变量和成员方法)不能被继承,以及父类中的构造方法也不能被继承
---父类也叫做超类,基类
子类也叫做派生类
---一个类只能继承一个直接的父类,也就是说类是单根性
---类具有传递性
class A{
//2个属性,3个方法
}
class B extends A{
//独有属性1个,独有方法2个
}
class C extends B{
}
28.6.super关键字
super表示父类,必须在子类中访问父类中的属性、方法也可以访问父类中的构造方法
注意:当使用super关键字访问父类中的构造方法,则必须编写在子类构造方法中,并且是第一条语句
.this关键字
this关键字可以访问当前类中的属性、方法以及构造方法
还可以访问父类中的属性、方法
28.7.当创建子类对象,父类做了什么?
----先执行父类的构造方法,然后再执行子类相匹配的构造方法
----如果子类构造方法中没有指明调用父类哪个构造方法,则默认调用父类的无参构造方法
----如果子类构造方法中指明调用父类哪个构造方法,通过super()或super(name,color,age),则调用父类相匹配的构造方法
29.多态:
多个对象调用同一个方法,则结果不同
class Person{ //属性 String name; int age; char sex; //构造方法 public Person(){ } public Person(String name,int age,char sex){ this.name = name; this.age = age; this.sex = sex; } //编写显示信息方法 public void show(){ System.out.println("姓名:" + this.name + " 年龄:" + this.age + " 性别:" + this.sex); } } //编写Student子类并继承Person父类 class Student extends Person{ //编写子类独有的属性:成绩 double score; //构造方法 public Student(){ } public Student(String name,int age,char sex,double score){ super(name,age,sex); this.score = score; } //编写学习的独有方法 public void study(){ System.out.println(super.name + "正在学习面向对象编程......"); } //重写显示信息方法 public void show(){ super.show(); System.out.println("成绩: " + score); } } //编写Teacher子类并继承Person父类 class Teacher extends Person{ //编写独有属性:薪资 double salary; //构造方法 public Teacher(){ } public Teacher(String name,int age,char sex,double salary){ super(name,age,sex); this.salary = salary; } //编写独有方法教学 public void teach(){ System.out.println(super.name + "正在讲面向对象编程课程。。。。。。"); } //重写父类的显示信息方法 public void show(){ super.show(); System.out.println("薪资:" + this.salary); } } //编写测试类 class Test{ public static void main(String[] args){ //创建Student对象 /*Student s = new Student(); //没有构成多态 s.show(); //先在学生类中找,如果没有找到则再去父类中找show方法*/ /*Person s2 = new Student(); //就是多态:多种形态,则只能访问父类中的属性和方法,但是优先访问子类重写以后的方法 s2.show(); //优先访问子类重写以后的方法 //s2.study(); //出现编译错误,原因:多态不能访问子类独有的属性和方法 System.out.println(s2.name); //null System.out.println(s2.age); //0 System.out.println(s2.sex); // //System.out.println(s2.score); //出现编译错误,原因:多态不能访问子类独有的属性和方法*/ //父类类名 引用名称 = new 子类类名(); /*Person p = new Student(); //构成多态 p.show(); //优先访问重写以后的方法 System.out.println(); Person p2 = new Teacher(); //构成多态 p2.show();*/ /*Teacher t = new Teacher(); //没有构成多态 t.show();*/ } } //编写第二个测试类 class Test2{ public static void main(String[] args){ //Student s = new Student(); //没有构成多态 /*System.out.println(s.name); //null System.out.println(s.age); //0 System.out.println(s.sex); System.out.println(s.score); //0.0 s.show(); s.study();*/ Person p = new Person(); //没有构成多态,注意:一般不实例化父类 /*System.out.println(p.name); //null System.out.println(p.age); //0 System.out.println(p.sex); */ //System.out.println(p.score); //编译错误 //p.show(); //访问父类中的show方法 Person person = new Student(); //构成多态,同时也是向上转型 person.show(); //必须将person引用名称转为Student类型,则才可以访问study方法 //person.study(); //编译错误 /*Student stu = (Student)person; //向下转型 stu.study(); Teacher t = (Teacher)person; //出现运行错误,原因:person引用中存放的是学生对象的地址,因此不能随意转为其他子类类型,建议在进行向下转型之前先进行判断,当合法进行向下转型,使用instanceof关键字 System.out.println(t.salary);*/ //在进行向下类型转换时可能会出现类型转换异常(java.lang.ClassCastException),进行判断 if(person instanceof Student){ //则强制转为学生 Student s = (Student)person; s.study(); }else if(person instanceof Teacher){ //则强制转为教师 Teacher t = (Teacher)person; t.teach(); } } }
29.1语法格式:
父类类名 引用名称 = new 子类类名(); //当构成多态时,只能访问父类中的属性和方法,但是优先访问子类重写以后的方法
29.2满足多态的条件:
1.必须子类继承父类
2.必须在子类中重写父类的方法
3.父类类名 引用名称 = new 子类类名();
6.3在多态中,有两种类型转换:
1.子类对象---->父类类型,称为向上转型或自动类型转换
如:Person p = new Student(); //构成多态,也是向上转型或自动类型转换
举个例子:有2个类,Father是父类,Son类继承自Father。
Father f1 = new Son(); // 这就叫 upcasting (向上转型)
// 现在f1引用指向一个Son对象
Son s1 = (Son)f1; // 这就叫 downcasting (向下转型)
当是向上转型时则只能访问父类中的属性和方法,但是优先访问子类重写以后的方法
2.父类引用名称---->子类类型,称为向下转型或强制类型转换
Student p = (Student)p;
*****注意:
1.当是多态时,并访问子类独有的属性或方法时则必须进行向下转型
2.在进行向下类型转换时可能会出现类型转换异常(java.lang.ClassCastException),建议先进行判断,满足在进行强制类型转换
30.递归:方法自己调用自己,但是必须保证要有出口
练习:使用递归完成计算n!,如:3!= 3 * 2 * 1