目录
1.本文主要内容简介
2.基础知识讲解
3.知识实际运用
4.总结
0.前言
前几篇文章基本上已经把类的大部分知识讲解完毕
本文开始讲解继承、多态等内容若想要了解“类”的主要知识,可以去看前面的文章
《[Java]开发安卓,你得掌握的Java知识5》
《[Java]开发安卓,你得掌握的Java知识4》
《[Java]开发安卓,你得掌握的Java知识3》由于最终目的是要开发安卓app,
因此这里使用的IDE是AS(Android Studio)
(不会使用的可以参考下面这篇文章中的例子)
《[Java]开发安卓,你得掌握的Java知识2》
1.本文主要内容简介
- 代码块
- 内部类
- 封装、继承、多态
- 一个实际的例子(思路、代码)
2.基础知识讲解
2.1什么是代码块
从观角度来说,
代码块就是在类中,用{ }括起来的部分从程序运行的角度来讲
代码块就像静态属性、方法一样,会早于对象被创建一个程序可以有多个代码块,执行顺序是从上倒下
但是注意:
尽可能不要写多个代码块(因为没有意义,可以写在一起)
class Person{
int age;
{
age = 20;
System.out.println("代码块 age="+age);
}
{
age=30
System.out.println("代码块 age="+age);
}
}
- 代码最后输出为:
代码块 age=20
代码块 age=30
- 用“static”修饰的代码块是静态代码块
静态代码块就和静态方法一样,会在对象创建前就被创建,因此
静态代码块只能调用静态属性、方法
static{
//静态代码块
}
2.2什么是内部类
按字面意思理解即可,内部类就是写在其他类内部的类
内部类出现的原因主要是因为某些类需要依附着别的类
定义内部类的好处在于:
(1)内部类实际上是一种很好的封装
(2)内部类拥有外围类的所有元素的访问权限
(3)内部类在外围类被某个子类继承时,内部类会跟着继承内部类的一些细节:
- 如果有内部类,一般会在外围类的属性中,
声明一个内部类变量(不赋值)
一般为了封装性好,我们不会让外部去调用我们的内部类,
即一般不能让Test.InnerTest.方法名()出现
(当然真这样写程序不会报错,但是封装性会变差)为了避免上面的这种情况,我们会在外围类的某个方法中,将已经声明过的内部类的变量用new进行赋值,然后根据内部类的构造方法等函数使用内部类
为了封装性,最关键就是让外部不知不觉地调用内部类,而不是显式调用
public class Test{
int count;
InnerTest inner;
class InnerTest{
//这是一个内部类
public InnerTest(){
//这是内部类的构造方法
count = 2;
show();
}
}
public void test(){
//这个函数是给外部调用的
inner = new InnerTest();
}
public void show(){
System.out.println("内部类构造函数被执行了");
}
}
public static void main(String[] args){
Test temp = new Test();
temp.test();
}
- 终端会输出:内部类构造函数被执行了
上面这段代码看似有点复杂,我们慢慢理一下
-
首先,外围类叫做Test,内部类叫做InnerTest
-
在上面代码的main函数中,我们创建了一个Test类(外围类)对象,然后调用了该类的一个对象方法test();
-
test()为Test中的inner属性用new进行赋值,使得内部类的构造函数被调用
-
内部类的构造函数中,调用了外围类的show(),所以终端输出了那句话
2.4什么是继承
某个准备编写的类A中的内容,和已存在的类B中很相似,或者A中的内容是B的一个延伸拓展,那么我们不会傻乎乎地再从头写一遍A
而是让A去继承Bclass A extends B , 表示类A是继承类B的
当A继承了B后,A就可以使用B的属性、方法(即使A中没有声明)
Java中只能单继承,不能多继承,最多只能间接多继承
即(A继承B,B继承C,相当于A继承C,变相多继承)所有的类都是直接或者间接继承与Object类
class Person{
protected String name;
protected int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void walk(){
System.out.println("走");
}
}
class Student extends Person{
public String school;
public int id;
public Student(String name, int age, int id, String school) {
super(name,age);
this.id = id;
this.school = school;
this.age = age;
this.name = name;
}
@Override
public void walk() {
System.out.print("学生优雅地");
super.walk();
}
}
上面代码的注意点:
父类为Person类,子类为Student类
父类想要保证属性的私有性,又要保证能够被继承,会让属性被protected修饰
public与protected修饰的属性是可以被继承的,但是private不行
如果父类中,已经写了一个有参的构造函数,那么子类再写有参的构造函数且要用到父类属性的时候,需要写一个super(参数...)
来说明哪些属性来自于父类2.5什么是重写
重写就是子类将父类的方法拿到自己这里进行修改
重写的方法一般会在上面加上 @Override,来表示这是重写的方法
重写与重载是两码事,
重写是针对继承来说的,是子类修改父类的方法
重载是针对一个类来说的,是类中会有多个同名的方法,但是这些方法的参数种类、数量,以及方法返回值都不尽相同
@Override
public void walk() {
System.out.print("学生优雅地");
super.walk();
}
上面的代码就是重写,其中super表示父类super.walk()就表示
这次重写除了自己新增那部分,还要用到父类的方法
2.6什么是多态
多态简单来说有两种体现:
(1)同一个方法(在不同类中)有多种不同的实现(与重载不一样)
(2)如果有继承关系(必须的前提,直接继承、间接继承都行)
子类的对象可以使用父类变量接收(叫做“类型的向上转换”)多态关注的是同一个方法在不同类中的实现,
重载是同一个方法名但是参数、返回值不同
class A{
}
class B extends A{
}
A test = new B();
Object test2 = new B();
List<Integer> list = new ArrayList<>();
这些都是多态的体现,当然更实际一些的应用在于:
class Person{}
class Student extends Person{}
class Teacher extends Person{}
Student s1 = new Student();
Teacher t1 = new Teacher();
ArrayList<Person> list = new ArrayList<>();
list.add(s1);
list.add(t1);
- 在写ArrayList的泛型的时候,如果要添加多种数据类型,而且这些数据类型都是继承的同一个类,那么就可以把这个统一的父类写在泛型中
3.实际应用
定义一个Person类:有name age两个属性
提供有参数的构造方法
walk方法
eat方法公务员:salary(工资) , show()
公司职员:salary ,会什么技术tec(字符串),show()创建多个职员和公务员 放到一个数组里面
将数组里面所有人的信息输出(把所有方法都显示出来)
要完成这个小程序,要一步步考虑:
(1)需要将多个人放到数组里
(2)放到数组里的要分为两种类型,公务员类和公司职员类
(3)这两个类都继承与Person类,还有自己的属性salary等
(4)Person类中有两个属性name age
以及两个方法walk(),eat()
(5)两个继承类均有自己的show()方法来展示信息
- 我们首先要定义一个Person类,并构造一个有参的构造方法。
这个父类基本不需要怎么处理,照着要求做即可
public class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void walk(){
System.out.println("人会走路");
}
public void eat(){
System.out.println("人会吃");
}
}
- 然后,我们需要按要求写两个继承类
Clerk(银行职员)和CivilServant(公务员)
没什么难度,因为子类没有什么额外的方法
public class Clerk extends Person {
public int salary;
private String tec;
public Clerk(String name, int age, int salary) {
super(name,age);
this.salary = salary;
}
@Override
public void walk() {
System.out.print(" 快跑 ");
}
@Override
public void eat() {
System.out.print(" 吃得快 ");
}
}
public class CivilServant extends Person {
public int salary;//薪水
public CivilServant(String name, int age, int salary) {
super(name,age);
this.salary = salary;
}
@Override
public void walk() {
System.out.print(" 大步走 ");
}
@Override
public void eat() {
System.out.print(" 大方吃 ");
}
}
- 接下来问题在于如何把人放入数组中
为了方便,我们定义几个静态数组来存放默认的人以及他们的信息,这些静态数组方法Constant类中
public class Constant {
public static String[] PERSONS = {"小王","小红","小黑","小蓝"};
public static int[] PERSONSAGES = {20,19,25,16};
public static String[] OCCUPATIONS= {"CivilServant","Clerk","CivilServant","Clerk"};
public static int CIVILSERVANTSALARY = 10000;
public static int CLERKSALARY = 5000;
public static String[] TEC= {"Android开发","iOS开发"};
}
有了这些信息之后,我们就需要将这些信息放入ArrayList中,由于CivilServant与Clerk虽然是不同的类,但是都继承于Person类
因此ArrayList的泛型就可以写<Person>为了封装性好一些,我们可以专门定义一个PersonManager,来处理人的信息(比如把信息打包放入数组中)
public class PersonManager {
public List<Person> personList = new ArrayList<>();
}
- 我们在PersonManager里面写一个方法来把静态数组中的信息放入personlist中
public void InfoInput(){
//用来将Constant类中的内容放入数组中
for (int i = 0; i < Constant.PERSONS.length; i++) {
if (Constant.OCCUPATIONS[i] == "CivilServant") {
this.personList.add(new CivilServant(Constant.PERSONS[i],Constant.PERSONSAGES[i],Constant.CIVILSERVANTSALARY));
}else{
//否则就是Clerk
this.personList.add(new Clerk(Constant.PERSONS[i],Constant.PERSONSAGES[i],Constant.CLERKSALARY));
}
}
}
- 其中,通过判定OCCUPATIONS来判断是那种职位,分别调用两种不同的构造函数(使用的是匿名对象)
所有信息都从Constant中定义好的静态数组中获取
- 最后我们写一个方法来输出,其中要注意的是,
父类是无法使用子类的方法的,要使用子类的方法,
就必须把父类强制转换为子类
如下面代码中的 Clerk c = (Clerk)p;,然后通过c调用show()方法
public void showWorkerInfo(){
//将所有人的所有信息都显示出来
for(Person p : personList){
if(p instanceof CivilServant){
CivilServant c = (CivilServant)p;
c.show();
}else{
//是银行职员
Clerk c = (Clerk)p;
c.show();
}
}
}
别忘记还要再两个继承类中添加show()方法:
public void show() {
System.out.print("name:" + this.name + " age:" + this.age + " salary:" + this.salary + " 公务员会");
this.walk();
this.eat();
System.out.println();
}
public void show() {
System.out.print("name:" + this.name + " age:" + this.age + " salary:" + this.salary + " 银行职员会");
this.walk();
this.eat();
System.out.println();
}
通过以上的封装后,主函数就可以写的比较清晰简洁了
public static void main(String[] args) {
//创建一个PersonManager对象
PersonManager personManager = new PersonManager();
//把所有人放入数组中
personManager.InfoInput();
//把输出所有人
personManager.showWorkerInfo();
}
输出结果为:
name:小王 age:20 salary:10000 公务员会 大步走 大方吃
name:小红 age:19 salary:5000 银行职员会 快跑 吃得快
name:小黑 age:25 salary:10000 公务员会 大步走 大方吃
name:小蓝 age:16 salary:5000 银行职员会 快跑 吃得快
ps:代码只是用来做个例子,输出结果没有任何其他意思
4.总结
(1)今天主要讲解了与类的继承有关的知识,继承、多态、封装也算是面向对象的灵魂,需要多多注意
(2)继承、多态等新知识,实际上理论都不难,但是如果想要灵活运用,还是需要多多练习
(3)可以发现,Java的代码编写一直都离不开“封装”的思想,因此,日后的学习中,锻炼这一思想,应该要当做一个重点看待。
网友评论