一个问题?[Demo107.java]
张老太养了两只猫猫:一只名字叫小白,今年3岁,白色。还有一只叫小花,今年100岁,花色。请编写一个程序,当用户输入小猫的名字时,就显示该猫的名字,年龄,颜色。如果用户输入的小猫名错误,则显示张老太没有这只猫猫。
//用前面学习过的知识写出代码
public class Demo107{
public static void main(String []args){
int a=49;//输入的名字49,50
int cat1age=3; //第一只猫
String cat1name="小白";
String cat1color="白色";
int cat2age=100; //第二只猫
String cat2name="小花";
String cat2color="花色";
switch(a){
case '1':
System.out.println(cat1age+cat1color);
break;
case '2':
System.out.println(cat2age+cat2color);
break;
default:
System.out.println("张老太没有这只猫!");
}
}
}
java语言是面向对象的
计算机语言的发展向接近人的思维方式演变
汇编语言 [面向机器]
c语言 [面向过程]
java语言 [面向对象]
类和对象的关系
把猫的特性提取出来-->猫类-->对象(实例)-->对象(实例)-->...
注意:从猫类到对象,目前有几种说法:
1、创建一个对象;
2、实例化一个对象;
3、对类实例化...以后大家听到这些说法,不要模糊。( 对象就是实例,实例就是对象)java最大的特点就是面向对象。
//定义猫类
public class Demo105{
public static void main(String []args){
//创建一个猫对象
Cat cat1=new Cat();//Cat是定义的一个数据类型
//Cat cat1;
//cat1=new Cat();// 等同于 Cat cat1=new Cat();
//访问属性的 对象名.属性名字
cat1.age=3;
cat1.name="小白";
cat1.color="白色";
//创建第二只猫
Cat cat2=new Cat();
cat2.age=100;
cat2.name="小花";
cat2.color="花色";
}
}
//java中如何定义一个类?[类名的首写字母大写]可根据程序的需要定义类
class Cat{
//下面的就是类的成员变量/属性
int agr;
String name;
String color;
Master myMaster;
}
//引用类型,比如建个主人类
class Master{
int age;
String name;
String address;
}
类和对象的区别和联系
1、类是抽象的,概念的,代表一类事物,比如人类,猫类..
2、对象是具体的,实际的,代表一个具体事物
3、类对象的模板,对象是类的一个个体,实例
类 -- 如何定义类
一个全面的类定义比较复杂,如:
package 包名;
class 类名 extends 父类 implements
接口名{
成员变量;
构造方法;
成员方法;
}
要透彻的掌握类,必须要了解类的构成
class 类名{ ----> 待定...
成员变量;
}
1. 类 -- 类的成员变量 :
成员变量是类的一个组成部分,一般是基本数据类型,也可是引用类型。比如我们前面定义猫类的int age 就是成员变量。
2. 对象 -- 如何创建对象 :
创建一个对象有两种方法
1、先声明再创建
1 、对象声明:类名 对象名
2 、对象创建:对象名=new 类名()
2、一步到位法
类名 对象名=new 类名()
对象--如何访问(使用)对象的成员变量
对象名 . 变量名; // 简单先这样理解,以后加下控制符此表达就不准确了。
一个小思考题[Demo.105.java]
为了让大家加深印象,我们定义一个人类(Person)(包括名字、年龄)。用一步到位法去创建一个对象
↓
我们看看下面一段代码:
System.out.printlin(b.age);
Person a=new Person(); → 请问:b.age究竟是多少?
a.age=10;
a.name="小明";
Person b;
b=a;
一个小思考题[Demo106.java]
在明白对象是如何在内存中存在后,请大家再看看下面的思考题,请问会输出什么信息?
Person1 a=new Person1();
a.age=10;
a.name="小明";
Person1 b;
b=a;
System.out.println(b.name);//输出“小明”
b.age=200;
System.out.println(a.age);//输出a.age为200
类--成员方法的初步介绍
在某些情况下,我们要需要定义成员方法。比如人类:除了有一些属性外(成员变量表示的年龄、姓名...),我们人类还有一些行为比如:可以说话、跑步..,通过学习,我们人类还可以做算术题。这时就要用成员方法才能完成。现在要求对Person类完善:
1、添加speak成员方法,输入出:我是一个好人
2、添加jisuan成员方法,可以计算从1+..+1000的结果
3、修改jisuan成员方法,该方法可以接收一个数n,计算从1+..+n的结果
4、添加add成员方法,可以计算两个数的和
3. 类 -- 类的成员方法 ( 成员函数 ) 定义 :
成员方法也叫成员函数,这里希望大家不要被两个名词搞晕了。
public 返回数据类型 方法名(参数列表)
{
语句;//方法(函数)主体
}
1、参数列表:表示成员函数输入
2、数据类型(返回类型):表示成员函数输出
3、函数主体:表示为了实现某一功能代码块
//类的调用及方法调用[Demo108.java]
public class Demo108{
public static void main(String []args){
Person p1=new Person();
p1.speak();//调用speak方法
p1.jiSuan();//调用计算方法
p1.jiSuan(200);//调用可以传入参数的计算方法
p1.add(12,10);//调用两个数的和
int res=p1.add2(23,34);//调用两个数的和并返回值到res中
System.out.println("res返回值是:"+res);
System.out.println("num1+num2+num3="+p1.add3(2,2.3f,4.5f));//返回类型一定要一致否则报错。
}
}
//定义名字的几个方法:
//1、驼峰法 如myCry;2、下划线法my_cry
//方法名在有不同参数的情况下可以使用同一个方法名,即有参数和没参数的方法可以同名
class Person{ //请注意类名首写字母应为大写如Person为类名
int age;
String name;
//1、可以输出我是好人方法
public void speak(){ //请注意方法名的首写字母应为小写如speak为方法名
System.out.println("我是一个好人");
}
//2、可以计算1+..+1000的方法
public void jiSuan(){
int result=0;
for(int i=1;i<=1000;i++){
result=result+i;
}
System.out.println("1+..+1000结果是"+result);
}
//3、带参数的成员方法,可以输入n值并计算1+..+n
public void jiSuan(int n){
int result=0;
for(int i=1;i<=n;i++){
result+=i;
}
System.out.println("1+..+n结果是"+result);
}
//4、计算两个数的和
public void add(int num1,int num2){
int result=0; //与下面一句等同于return num1+num2;
result=num1+num2;
System.out.println("num1+num2="+result);
}
//5、计算两个数的和,并将结果返回给主调(调用它的)函数
//注意:返回类型和返回结果的类型要一致
//注意:在调用某个成员方法的时候,给出的具体数值的个数
//和类型要相匹配。
public int add2(int num1,int num2){
return num1+num2;
}
//6、计算两个float数的和,并将结果返给主调函数
public float add3(int num1,float num2,float num3){
return num1+num2+num3;
}
}
类 -- 类的成员方法(函数)--如何理解
如何理解方法这个概念,给大家举个通俗的示例:
程序员调用方法:给方法必要的输入,方法返回结果。
类的成员方法-- 声明 :
public int test(int a);/*方法声明*/
这句话的作用是声明该方法,声明的格式为:
访问修饰符 数据类型 函数名(参数列表);
在给Person类添加add方法的例题中,我们看到的关键字return ,它的功能是把表达式的值返回的值返回给主调函数的方法。
return 表达式;
类的成员方法(函数)--特别说明
1、方法的参数列表可以是多个
案例:在Person类中编写一个成员方法,从键盘输入三个数,返回最大的那个数。
参数列表可以是多个,并且数据类型可以是任意的类型int float double char..
访问修饰符 返回数据类型 函数名(参数列表){
语句; //函数主体
}
2、方法可以没有返回值
案例:编写一个函数,从控制台输入一个整数打印出对应的金字塔。
返回类型可以是任意的数据类型(int,float,double,char..)也可以没有返回值void表示没有返回值
访问修饰符 返回数据类型 函数名(形参列表){
语句; //函数主体
}
类的成员方法(函数)--小练习
案例:编写一个成员函数,从键盘输入一个整数(1-9),打印出对应的乘法表[Demo110.java]
//实例键盘输入打印乘法表[Demo110.java]
import java.io.*;
public class Demo110{
public static void main(String []args){
Cfb jiu=new Cfb();
jiu.cf();
}
}
class Cfb{
public void cf(){
try{
//输入流,从键盘接收数
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br=new BufferedReader(isr);
//给出提示
System.out.println("请输入1-9,按0退出:");
//从控制台读取一行数据
String a1=br.readLine();
//把String转为int
int num1=Integer.decode(a1);
for(int i=1;i<=num1;i++){
for(int j=1;j<=i;j++){
System.out.print(i+"×"+j+"="+(i*j)+"\t");
}
System.out.println();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
案例:编写函数,使给定的一个二维数组(3×3)转置
类定义的完善
在介绍了成员方法后,我们类的定义就可以完善一步:
class 类名{ class 类名{ 待定
成员变量; → 成员变量; →
} 成员方法;
}
小结:1.先设计类;2.然后根据类创建对象。
小练习:
1、设计计算机类,要求如下:[Demo109.java]
属性:品牌(Brand)、颜色(Color)、cpu型号(CPU)、内存容量(Memory)、硬盘大小(Harddisk)、价格(Price)、工作状态(Work)
方法:打开(Open)、关闭(Close)、休眠(Sleep)
创建一个计算机对象,调用打开,关闭方法
//计算机类与对象的代码
import java.io.*;//加载IO流包
public class Demo109{
public static void main(String []args){
Computer Pc=new Computer();
Pc.Brand="品牌";
Pc.Color="颜色";
Pc.Cpu="Cpu型号";
Pc.Memory="内存容量";
Pc.Hd="硬盘容量";
Pc.Price="价格";
Pc.Work="工作状态";
try{
//输入流,从键盘接收数
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br=new BufferedReader(isr);
//给出提示
System.out.println("请输入0-9控制机器");
//从控制台读取一行数据
String a1=br.readLine();
//把String转为float
float num1=Float.parseFloat(a1);
if(num1==0){Pc.open();}
else if(num1==1){Pc.close();}
else if(num1==2){Pc.sleep();}
else if(num1==3){System.out.println(Pc.Brand);}
else if(num1==4){System.out.println(Pc.Color);}
else if(num1==5){System.out.println(Pc.Cpu);}
else if(num1==6){System.out.println(Pc.Memory);}
else if(num1==7){System.out.println(Pc.Hd);}
else if(num1==8){System.out.println(Pc.Price);}
else if(num1==9){System.out.println(Pc.Work);}
else {System.out.println("输入错误!");}
}catch(Exception e){
e.printStackTrace();
}
}
}
class Computer{
String Brand;
String Color;
String Cpu;
String Memory;
String Hd;
String Price;
String Work;
public void open(){
System.out.println("开机");
}
public void close(){
System.out.println("关机");
}
public void sleep(){
System.out.println("休眠");
}
}
1、 采用面向对象思想设计超级马里奥游戏人物
类的构造方法介绍
什么是构造方法呢?在回答这个问题之前,我们来看一个需求:前面我们在创建人类的对象时,是先把一个对象创建好后,再给他的年龄和姓名属性赋值,如果现在我要求,在创建人类的对象时,就直接指定这个对象的年龄和姓名,该怎么做?
↓
你可以在定义类的时候,定义一个构造方法即可。
构造方法是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。它有几个特点:
1、方法名和类名相同
2、没有返回值
3、在创建一个类的新对象时,系统会自动的调用该类的构造方法完成对新对象的初始化。
特别说明:
一个类可以定义多个不同的构造方法。
//例人类构造方法[Demo111.java]
public class Demo111{
public static void main(String []args){
Person p1=new Person(12,"顺平");//给予不同的初始值,调用的构造方法不同,构造方法虽同名,但系统会根据初始值来选定构造方法。
}
}
//定义一个人类
class Person{
int age;
String name;
//默认构造方法
public Person(){
}
//构造方法的主要用处是:初始化你的成员属性(变量)
//构造方法
public Person(int age,String name){
System.out.println("我是构造1");
age=age;
name=name;
}
//构造方法2
public Person(String name){
System.out.println("我是构造2");
name=name;
}
}
类的默认构造方法
有些同志可能会问?亲爱的老师,我们在没有学习构造函数前不是也可以创建对象吗?
是这样的,如果程序员没有定义构造方法,系统会自动生成一个默认构造方法。比如Person类Person (){};
当创建一个Person对象时Person per1=new Person();默认的构造函数就会被自动调用。
类的构造方法小结:
1 、构造方法名和类名相同;
2 、构造方法没有返回值;
3 、主要作用是完成对新对象的初始化;
4 、在创建新对象时,系统自动的调用该类的构造方法;
5 、一个类可以有多个构造方法;
6 、每个类都有一个默认的构造方法。
类定义的改进
在提出构造方法后,我们类的定义就应该更加完善了:
class 类名{ class 类名{ class 类名{
成员变量; 成员变量; 成员变量;
} → 成员方法; → 构造方法; → 待定..
} 成员方法
}
一个问题?
请大家看一段代码:(Demo112.java)
重点:this是属于一个对象,不属于类的。
java虚拟机会给每个对象分配this,代表当前对象。坦白的讲,要明白this不是件容易的事
注意事项:this不能在类定义的外部使用,只能在类定义的方法中使用
/*
this的必要性
*/
public class Demo112{
public static void main(String []args){
Dog dog1=new Dog(2,"大黄");
Person p1=new Person(dog1,23,"郭德纲");
Person p2=new Person(dog1,24,"刘谦");
p1.showInfo();
p1.dog.showInfo();
}
}
//定义一个人类
class Person{
//成员变量
int age;
String name;
Dog dog;//引用类型
public Person(Dog dog,int age,String name){
//可读性不好
//age=age;
//name=name;
this.age=age; //this.age指this代词指定是成员变量age
this.name=name; //this.name指this代词指定是成员变量name
this.dog=dog;
}
//显示人名字
public void showInfo(){
System.out.println("人名是:"+this.name);
}
}
class Dog{
int age;
String name;
public Dog(int age,String name){
this.age=age;
this.name=name;
}
//显示狗名
public void showInfo(){
System.out.println("狗名叫"+this.name);
}
}
类变量--提出问题?
提出问题的主要目的就是让大家思考解决之道。
public class Demo113{
public static void main(String []args){
/* int total=0;
Child ch1=new Child(3,"妞妞");
ch1.joinGame();
total++;
Child ch2=new Child(4,"小小");
ch2.joinGame();
total++;
*/
Child ch1=new Child(3,"妞妞");
ch1.joinGame();
Child ch2=new Child(4,"小小");
ch2.joinGame();
Child ch3=new Child(5,"大大");
ch3.joinGame();
System.out.println("共有="+Child.total);
}
}
//定义小孩类
class Child{
int age;
String name;
//static公共函数,total是静态变量,因此它可以被任何一个对象访问
static int total=0;
public Child(int age,String name){
this.age=age;
this.name=name;
}
public void joinGame(){
total++;
System.out.println("有一个小孩加入了");
}
}
什么是类变量?
类变量是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。
如何定义类变量?
定义语法:
访问修饰符 static 数据类型 变量名;
如何访问类变量?
类名 . 类变量名 或者 对象名 . 类变量名
//类变量的程序演示[Demo114.java]
public class Demo114{
static int i=1;
static{
//该静态区域块只被执行一次
i++;
System.out.println("执行一次");
}
public Demo114(){ //建立Demo114()构造函数
System.out.println("执行二次");
i++;
}
public static void main(String []args){
Demo114 t1=new Demo114(); //创建t1对象实例并调用Demo114函数
System.out.println(t1.i);
Demo114 t2=new Demo114();
System.out.println(t2.i);
}
}
什么是类方法,为什么有类方法?
类方法是属于所有对象实例的,其形式如下:
访问修饰符 static 数据返回类型 方法名(){}
注意:类方法中不能访问非静态变量(类变量)。
使用:类名 . 类方法名 或者 对象名 . 类方法名
重点static静态的方法可以访问static静态变量,不能访问非静态变量(类变量)
非静态方法可以访问非静态变量(类变量)同时也可以访问static静态变量。
//统计总学费的程序代码,加深static静态的方法由静态变量的访问[Demo115.java]
public class Demo115{
public static void main(String []args){
//创建一个学生
Stu stu1=new Stu(29,"aa",340);
Stu stu2=new Stu(29,"aa",240);
System.out.println(Stu.getTotalFee());
}
}
//学生类
class Stu{
int age;
String name;
int fee;
static int totalFee;
public Stu(int age,String name,int fee){
this.age=age;
this.name=name;
totalFee+=fee;
}
//返回总学费[这是一个类方法(静态方法)]
//java中规则:类变量原则上用类方法去访问或操作
public static int getTotalFee(){
return totalFee;
}
}
类变量小结
1、什么时候需要用类变量
案例[Demo115.java]:定义学生类,统计学生共交多少钱?
用类变量,属于公共的属性
2、类变量与实例变量区别:
加上static称为类变量或静态变量,否则称为实例变量
类变量是与类相关的,公共的属性
实例变量属于每个对象个体的属性
类变量可以通过 [类名 . 类变量名] 直接访问
类方法小结
1、什么时候需要用类方法
案例[Demo115.java]:定义学生类,统计学生共交多少钱?
类方法属于与类相关的,公共的方法
实例方法属于每个对象个体的方法
类方法可以通过 [类名 . 类方法名] 直接访问
java 面向对象编程的四大特征
抽象/封装/继承/多态
1 抽象 :
1、简单理解
我们在前面去定义一个类时候,实际上就是把一类事物的共有的属性和行为提取出来,形成一个物理模型(模版)。这种研究问题的方法称为抽象。
封装--什么是封装
封装就是把抽象出来的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员方法),才能对数据进行操作。
封装--访问控制修饰符
电视机的开关,对音量,颜色,频道的控制是公开的,谁都可以操作,但是对机箱后盖,主机板的操作却不是公开的,一般是由专业维修人员来玩。那么java中如何实现这种类似的控制呢?不能随便查看人的年龄,工资等隐私[Demo116.java]
//封装案例[Demo116.java]
public class Demo116{
public static void main(String []args){
//创建一个职员
Clerk clerk1=new Clerk("小花",24,4567.6f);
System.out.println("名字是"+clerk1.name+"薪水"+clerk1.getSal());
}
}
//职员
class Clerk{
public String name;
//private私有的,public公有的
private int age;
private float salary;
public Clerk(String name,int age,float sal){
this.name=name;
this.age=age;
this.salary=sal;
}
//通过一个成员方法去控制和访问私有的属性
public float getSal(){
return this.salary;
}
}
2. 封装 -- 访问控制修饰符 :
java提供四种访问控制修饰符号控制方法和变量的访问权限:
1 、公开级别:用public修饰,对外公开
2 、受保护级别:用protected修饰,对子类和同一个包中的类公开
3 、默认级别:没有修饰符号,向同一个包的类公开
4 、私有级别:用private修饰,只有类本身可以访问,不对外公开
包--必要性
问题的提出,请看下面的一个场景[eclipse]
现在有两个程序员共同开发一个java项目,程序员xiaoming希望定义一个类取名Dog,程序员xiaoqiang也想定义一个类也叫Dog。两个程序员为此还吵了起来,怎么办?
包 -- 三大作用
1、区分相同名字的类
2、当类很多时,可以很好的管理类
3、控制访问范围
包 -- 换包命令
package com. 自定义名字;
注意:打包命令一般放在文件开始处。
包--命名规范
小写字母 比如 com.sina.shunping
包--常用的包
一个包下,包含很多的类,java中常用的包有:
java.lang.* 包 自动引入 java.util.* 工具包
java.net.* 包 网络开发包 java.awt.* 包 窗口工具包
包--如何引入包
语法:import 包;
比如import java.awt.*;
我们引入一个包的主要目的要使用该包下的类
定义类的改进
在提出包后,我们类的定义就更加完善了:
class 类名{ class 类名{ class类名{ package包名; 待定..
成员变量; → 成员变量; → 成员变量; → class 类名{ →
} 成员方法; 构造方法; 成员变量;
} 成员方法; 构造方法;
} 成员方法;
}
3继承--为什么有?
//功能:说明继承的重要性
package com.abc;//包名
public class Demo117 {
public static void main(String[] args) {
Pupil p1=new Pupil();
p1.printName();
}
}
//将学生的共有属性提取,做一个父类
class Stu{
//定义成员属性
protected int age;
public String name;
public float fee;
private String job;//私有将不被继承
//编程中,如果你不希望子类继承某个属性或方法
//则将其声明为private即可
public void printName(){
System.out.println("名字"+this.name);
}
}
//小学生类
class Pupil extends Stu{
//交学费
public void pay(float fee){
this.fee=fee;
}
}
//幼儿
class Pre extends Pupil{
//交学费
public void pay(float fee){
this.fee=fee*1.5f;
}
}
//中学生类
class MiddleStu extends Stu{
//交学费
public void pay(float fee){
this.fee=fee*0.8f;
}
}
//大学生类
class ColStu extends Stu{
//交学费
public void pay(float fee){
this.fee=fee*0.1f;
}
}
继承 -- 解决之道
继承可以解决代码复用,让我们的编程更加靠近人类思维。当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类(比如刚才的Student),在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends语句来声明继承父类:
语法:class 子类 extends 父类
这样,子类就会自动拥有父类定义的某些属性和方法。
继承--深入讨论
1、父类的哪些属性(变量)、方法被子类继承了?并不是父类的所有属性、方法都可以被子类继承
父类 子类
public 属性; public 属性;
protected 属性; 继承 protected 属性;
private 属性; → 属性;
属性;
public 方法; public 方法;
protected 方法; protected 方法;
private 方法; 方法;
方法;
2、结论
从图可以看出,父类的public修饰符的属性和方法;protected修饰符的属性和方法;默认修饰符属性和方法被子类继承了,父类的private修饰符的属性和方法不能被子类继承。
继承--注意事项
1、子类最多只能继承一个父类(指直接继承)
2、java所有类都是Object类的子类 (所有的子类都可以逐级继承,例:爷->父->子->孙)
3、JDK6中有202个包3777个类、接口、异常、枚举、注释和错误
4、在做开发的时候,强烈建议大家多查jdk帮助文档
5、在使用类时,实在不知道怎么办,多使用搜索引擎
4. 定义类的改进 :
在提出包后,我们类的定义就更加完善了:
class 类名{ class 类名{ class类名{ package包名;
成员变量; → 成员变量; → 成员变量; → class 类名{
} 成员方法; 构造方法; 成员变量;
} 成员方法; 构造方法;
} 成员方法;
} ↓
↓←←←←←←←←←←←←←←←←←←←←←←←←←
package 包名;
class 类名 extends 父类{ 待定
成员变量; → ....
构造方法;
成员方法;
}
1 方法重载 (overload)
按顺序,我们应该讲解多态,但是在讲解多态前,我们必须讲解方法重载和方法覆盖(override)。
请编写一个类(Abc),编写方法可以接收两个整数,返回两个数中较大的数[Demo119.java]
//方法重载(overload)getMax
public class Demo119{
public static void main(String []args){
Abc2 abc1=new Abc2();
System.out.println(abc1.getMax(12,14));
System.out.println(abc1.getMax(24f,20f));
}
}
class Abc2{
//返回较大的整数
public int getMax(int i,int j){
if(i>j){
return i;
}else{
return j;
}
}
public float getMax(float a,float b){
if(a>b){
return a;
}else{
return b;
}
}
//如果只是返回类型不一样,能否构成重载?不能够构成重载
/* public double getMax(float d,double c){
if(c>d){
return c;
}else{
return d;
}
}
//如果只是控制访问修饰符不同,能否构成重载?不能够构成重载
protected float getMax(float c,float d){
if(c>d){
return c;
}else{
return d;
}
}*/
}
方法重载(overload) 概念
简单的说:方法重载就是在类的同一种功能的多种实现方式,到底采用哪种方式,取决于调用者给出的参数。
注意事项:
1、方法名相同
2、方法的参数类型,个数,顺序至少有一项不同
3、方法返回类型可以不同(只是返回类型不一样,不能构成重载)
4、方法的修饰符可以不同(只是控制访问修饰符不同,不能构成重载)
2 方法覆盖 (override)
既然子类可以继承父类的属性和方法,这样可以提高代码的复用性,这个很好,可是问题来了,假设现在我要求大家写三个类猫猫,狗狗,猪猪。我们知道这三个东东都是动物,动物必然存在相同的特点。根据类的抽象特征,我们可以把它们的相同点提取出来,形成一个父类,然后继承。
//子类方法覆盖父类方法[Demo120.java]
public class Demo120{
public static void main(String []args){
//创建一只猫
Cat cat1=new Cat();
cat1.cry();
Dog dog1=new Dog();
dog1.cry();
}
}
//动物类
class Animal{
int age;
String name;
//都会叫
public void cry(){
System.out.println("我是动物,不知道怎么叫");
}
}
//猫猫类
class Cat extends Animal{
//覆盖父类方法
public void cry(){
System.out.println("猫猫叫!");
}
}
//狗狗类
class Dog extends Animal{
//覆盖父类方法
public void cry(){
System.out.println("汪汪叫!");
}
}
方法覆盖(override)概念
简单的说:方法覆盖就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的那个方法。比如上个案例的Cat类中的cry方法就覆盖了Animal类的cry方法。
注意事项:
方法覆盖有很多条件,有些书上说的比较细,总的讲有两点一定注意:
1、子类的方法的返回类型,参数,方法名称,要和父类的返回类型,参数,方法名称完全一样,否则编译出错。
2、子类方法不能缩小父类方法的访问权限。
===============================================================================
作业:上机实习题目
1、Josephu问题(丢手帕问题)
Josephu问题为:设编号为1,2,...n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
提示:用一个不带头结点的循环链表来处理Josephu问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点的人从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。
//Josephu问题(丢手帕问题)
//使用单向链表
public class Demo121 {
public static void main(String[] args) {
CycLink cyclink=new CycLink();
cyclink.setLen(5);//链表长度
cyclink.createLink();
cyclink.setK(2);//从第几个人开始数
cyclink.setM(2);//数几下
cyclink.show();
cyclink.play();
}
}
class Child{
int no;
Child nextChild=null;
public Child(int no){
//给一个编号
this.no=no;
}
}
//单向环形链表
class CycLink{
//先定义一个指向链表第一个小孩的引用
//指向第一个小孩的引用,不能动
Child firstChild=null;
Child temp=null;
int len=0;//表示共有多少个小孩
int k=0;
int m=0;
//设置m数几下
public void setM(int m){
this.m=m;
}
//设置环形链表大小
public void setLen(int len){
this.len=len;
}
//设置从第几个人开始数数
public void setK(int k){
this.k=k;
}
//开始play
public void play(){
Child temp=this.firstChild;
//1.先找到开始数数的人
for(int i=1;i
1多态-- 概念
所谓多态,就是指一个引用(类型)在不同情况下的多种状态。也可以理解成:多态是指通过指向父类的指针,来调用在不同子类中实现的方法。
实现多态有两种方式:1、继承;2、接口
多态演示[Dome122.java]
//演示继承、方法覆盖、多态
public class Demo122 {
public static void main(String[] args) {
//非多态演示
Cat cat=new Cat();
cat.cry();
Dog dog=new Dog();
dog.cry();
//多态演示
Animal an=new Cat();
an.cry();
an=new Dog();
an.cry();
}
}
//动物类
class Animal{
String name;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//动物会叫
public void cry(){
System.out.println("不知道怎么叫");
}
}
//创建Dog子类并继承Animal父类及覆盖cry方法
class Dog extends Animal{
//狗叫
public void cry(){
System.out.println("汪汪叫");
}
}
class Cat extends Animal{
//猫自己叫
public void cry(){
System.out.println("猫猫叫");
}
}
2 多重多态演示[Dome123.java]
//演示子类继承父类、方法覆盖、多态方法
public class Demo123 {
public static void main(String[] args) {
//非多态演示
System.out.println("非多态演示:");
Cat cat=new Cat();
cat.cry();
Dog dog=new Dog();
dog.cry();
System.out.println();
//多态演示
System.out.println("多态演示:");
Animal an=new Cat();
an.cry();
an=new Dog();
an.cry();
System.out.println();
//多重多态演示
System.out.println("多重多态演示:");
Master master=new Master();
master.feed(new Dog(),new Bone());
master.feed(new Cat(),new Fish());
}
}
//主人类
class Master{
//给动物喂食物,使用多态,只要写一个方法
public void feed(Animal an,Food f){
an.eat();
f.showName();
}
}
//食物父类
class Food{
String name;
public void showName(){
System.out.println("食物");
}
}
//食物鱼子类
class Fish extends Food{
public void showName(){
System.out.println("鱼");
}
}
//食物骨头子类
class Bone extends Food{
public void showName(){
System.out.println("骨头");
}
}
//动物类Animal父类
class Animal{
String name;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//动物会叫
public void cry(){
System.out.println("不知道怎么叫");
}
//动物吃东西
public void eat(){
System.out.println("不知道吃什么");
}
}
//创建Dog子类并extends继承Animal父类及覆盖cry方法
class Dog extends Animal{
//狗叫
public void cry(){
System.out.println("汪汪叫");
}
//狗吃东西
public void eat(){
System.out.println("狗爱吃骨头");
}
}
class Cat extends Animal{
//猫自己叫
public void cry(){
System.out.println("猫猫叫");
}
//猫吃东西
public void eat(){
System.out.println("猫爱吃鱼");
}
}
3 多态 -- 注意事项:
1、java允许父类的引用变量引用它的子类的实例(对象)
Animal an=new Cat();//这种转换时自动完成的
2、关于类型转换还有一些具体的细节要求,我们在后面还要提,比如子类能不能转换成父类,有什么要求等等...
1 抽象类 -- 解决之道
当父类的一些方法不能确定时,可以用abstract关键字来修饰该方法[抽象方法],用abstract来修饰该类[抽象类]。
//抽象类的必要性[Demo124.java]
public class Demo124 {
public static void main(String[] args) {
//Animal an=new Animal();抽象类不允许实例化
Animal an=new Cat();
an.cry();
an=new Dog();
an.cry();
}
}
//抽象类abstract关键词
abstract class Animal{
String name;
int age;
//动物会叫,使用了abstract抽象方法
abstract public void cry();//抽象类中可以没有abstract抽象方法
//抽象类内可以有实现方法
public void sx(){
System.out.println("实现方法");
}
}
//当一个子类继承的父类是abstract抽象类的话,需要程序员把抽象类的抽象方法全部实现。
class Cat extends Animal{
//实现父类的cry,其实类似上节学习中的子类覆盖父类
public void cry(){
System.out.println("猫猫叫");
}
}
class Dog extends Animal{
//实现父类的cry,其实类似上节学习中的子类覆盖父类
public void cry(){
System.out.println("汪汪叫");
}
}
2 抽象类 -- 深入讨论
抽象类是java中一个比较重要的类。
1 、用abstract关键字来修饰一个类时,这个类就是抽象类。
2 、用abstract关键字来修饰一个方法时,这个方法就是抽象方法。
3 、abstract抽象类中的abstract抽象方法是不允许在抽象类中实现的,一旦实现就不是抽象方法和抽象类了。abstract抽象方法只能在子类中实现。
4 、抽象类中可以拥有实现方法。
5、抽象方法在编程中用的不是很多,但是在公司笔试时,却是考官比较爱问的知识点。
3 抽象类****--****注意事项
1 、抽象类不能被实例化
2 、抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract抽象方法。
3 、一旦类包含了abstract抽象方法,则这个类必须声明为abstract抽象类。
4 、抽象方法不能有主体。
正确的抽象方法例:abstract void abc();
错语的抽象方法例:abstract void abc(){}
1 接口 -- 为什么有?
USB插槽就是现实中的接口。
什么是接口?
接口就是给出一些没有内容的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。
接口的建立语法:interface 接口名 { 方法;}
语法:class 类名 implements 接口 {
方法;
变量;
}
小结:接口是更加抽象的抽象的类,抽象类里的方法可以有方法体,接口里的所有方法都没有方法体。接口体现了程序设计的多态和高内聚低偶合的设计思想。
2 接口 -- 注意事项
1、接口不能被实例化
2、接口中所有的方法都不能有主体。错误语法例:void aaa(){}←(注意不能有花括号)
接口可以看作更加抽象的抽象类。
3、一个类可以实现多个接口
4、接口中可以有变量[但变量不能用private和protected修饰]
a、接口中的变量,本质上都是static的而且是final类型的,不管你加不加static修饰
b、在java开发中,我们经常把常用的变量,定义在接口中,作为全局变量使用
访问形式:接口名 . 变量名
5、一个接口不能继承其它的类,但是可以继承别的接口
//接口的实现[Demo125.java]
//电脑,相机,u盘,手机
//usb接口
interface Usb{
int a=1;//加不加static都是静态的,不能用private和protected修饰
//声明了两个方法
public void start();//接口开始工作
public void stop();//接口停止工作
}
//编写了一个相机类,并实现了usb接口
//一个重要的原则:当一个类实现了一个接口,要求该类把这个接口的所有方法全部实现
class Camera implements Usb{
public void start(){
System.out.println("我是相机,开始工作了..");
}
public void stop(){
System.out.println("我是相机,停止工作了..");
}
}
//接口继承别的接口
class Base{
}
interface Tt{
}
interface Son extends Tt{
}
//编写了一个手机,并实现了usb接口
class Phone implements Usb{
public void start(){
System.out.println("我是手机,开始工作了..");
}
public void stop(){
System.out.println("我是手机,停止工作了..");
}
}
//计算机
class Computer{
//开始使用usb接口
public void useUsb(Usb usb){
usb.start();
usb.stop();
}
}
public class Demo125 {
public static void main(String[] args) {
System.out.println(Usb.a);
//创建 Computer
Computer computer=new Computer();
//创建Camera
Camera camera1=new Camera();
//创建Phone
Phone phone1=new Phone();
computer.useUsb(camera1);
computer.useUsb(phone1);
}
}
3 定义类的改进
有了接口,我们类的定义就更加完善了:
class 类名{ class 类名{ class类名{ package包名;
成员变量; → 成员变量; → 成员变量; → class 类名{
} 成员方法; 构造方法; 成员变量;
} 成员方法; 构造方法;
} 成员方法;
} ↓
↓←←←←←←←←←←←←←←←←←←←←←←←←←
package 包名; package 包名;
class 类名 extends 父类{ class 类名 extends 父类 implements 接口名{
成员变量; → 成员变量;
构造方法; 构造方法;
成员方法; 成员方法;
} }
4 实现接口VS继承类
java的继承是单继承,也就是一个类最多只能有一个父类,这种单继承的机制可保证类的纯洁性,比C++中的多继承机制简洁。但是不可否认,对子类功能的扩展有一定影响。所以:
1、实现接口可以看作是对继承的一种补充。(继承是层级式的,不太灵活。修改某个类就会打破继承的平衡,而接口就没有这样的麻烦,因为它只针对实现接口的类才起作用)
2、实现接口可在不打破继承关系的前提下,对某个类功能扩展,非常灵活。
//实例:建立子类并继承了父类且连接多个接口[Demo126.java]
public class Demo126 {
public static void main(String[] args) {
System.out.println("继承了Monkey父类");
Monkey mo=new Monkey();
mo.jump();
LittleMonkey li=new LittleMonkey();
li.swimming();
li.fly();
}
}
//接口Fish
interface Fish{
public void swimming();
}
//接口Bird
interface Bird{
public void fly();
}
//建立Monkey类
class Monkey{
int name;
//猴子可以跳
public void jump(){
System.out.println("猴子会跳!");
}
}
//建立LittleMonkey子类并继承了Monkey父类并连接了Fish和Bird接口
class LittleMonkey extends Monkey implements Fish,Bird{
public void swimming() {
System.out.println("连接了Fish接口!");
}
public void fly() {
System.out.println("连接了Bird接口!");
}
}
5 用接口实现多态--案例[Demo127.java]
java中多态是个难以理解的概念,但同时又是一个非常重要的概念。java三大特性之一(继承,封装,多态),我们可以从字面上简单理解:就是一种类型的多种状态,以下通过卖小汽车的例子说明什么是多态。
//用接口实现多态
public class Demo127 {
public static void main(String []args){
CarShop aShop=new CarShop();
//卖出一辆宝马
aShop.sellCar(new BMW());
//卖出一辆奇瑞QQ
aShop.sellCar(new CheryQQ());
//卖出一辆桑塔纳
aShop.sellCar(new Santana());
System.out.println("总收入:"+aShop.getMoney());
}
}
//汽车接口
interface Car{
//汽车名称
String getName();
//获得汽车售价
int getPrice();
}
//宝马
class BMW implements Car{
public String getName(){
return "BMW";
}
public int getPrice(){
return 300000;
}
}
//奇瑞QQ
class CheryQQ implements Car{
public String getName(){
return "CheryQQ";
}
public int getPrice(){
return 20000;
}
}
//桑塔纳汽车
class Santana implements Car{
public String getName(){
return "Santana";
}
public int getPrice(){
return 80000;
}
}
//汽车出售店
class CarShop{
//售车收入
private int money=0;
//卖出一部车
public void sellCar(Car car){
System.out.println("车型:"+car.getName()+"单价:"+car.getPrice
());
//增加卖出车售价的收入
money+=car.getPrice();
}
//售车总收入
public int getMoney(){
return money;
}
}
运行结果:
车型:BMW 单价:300000
车型:CheryQQ 单价:20000
总收入:320000
继承是多态得以实现的基础。从字面上理解,多态就是一种类型(都是Car类型)表现出多种状态(宝马汽车的名称是BMW,售价是300000;奇瑞汽车的名称是CheryQQ,售价是2000)。将一个方法调用同这个方法所属的主体(也就是对象或类)关联起来叫做绑定,分前期绑这下和后期绑定两种。下面解释一下它们的定义:
1 、前期绑定:在程序运行之前进行绑定,由编译器和连接程序实现,又叫做静态绑定。比如static方法和final方法,注意,这里也包括private方法,因为它是隐式final的。
2 、后期绑定:在运行时根据对象的类型进行绑定,由方法调用机制实现,因此又叫做动态绑定,或者运行时绑定。除了前期绑定外的所有方法都属于后期绑定。
多态就是在后期绑定这种机制上实现的。多态给我们带来的好处是消除了类之间的偶合关系,使程序更容易扩展。比如在上例中,新增加一种类型汽车的销售。只需要让新定义的类实现Car类并实现它的所有方法,而无需对原有代码做任何修改,CarShop类的sellCar(Car
car)方法就可以处理新的车型了。
新增代码如下:
java代码
//桑塔纳汽车
class Santana implements Car{
public String getName(){
return "Santana";
}
public int getPrice(){
return 80000;
}
}
final概念
final中文意思:最后的,最终的。
final可以修饰变量或者方法。
在某些情况下,程序员可能有以下需求:
1 、当不希望父类的某个方法被子类覆盖(override)时,可以用final关键字修饰。
2 、当不希望类的某个变量的值被修改,可以用final修饰。如果一个变量是final,则必须赋初值,否则编译出错。
3 、当不希望类被继承时,可以用final修饰。
//final方法的使用[Demo128.java]
public class Demo128 {
public static void main(String[] args) {
Aaa aaa=new Aaa();
aaa.show();
Bbb bbb=new Bbb();
bbb.show();
}
}
class Aaa{
int a=0;//如果a不赋初值,a是0。定义类型后应赋值
//圆周率不让修改
//带有final修饰的变量命名时应有_下划线来区分表示。这是java程序员的标准。
final float reate_1=3.1415926f;//使用final可以保证,需要强制不被修改的数据一定要用final锁定
//final int b; //使用final定义变量时一定要赋初值否则报错。
//b=1;
final public void sendMes(){//给成员方法用final来修饰则表示不可以被修改,不可被覆盖。
System.out.println("发送消息");
}
public void show(){
System.out.println("a="+a);
}
}
final class Bbb extends Aaa{//定义类前加final表示该类不允许被继承
public Bbb(){
a++;
//reate_1=reate+1;
}
/*public void sendMes(){
System.out.println("发送消息")
}*/
}
final-- 注意事项
1、final修饰的变量又叫常量,一般用XX_XX_XX来命名。(带下划线)
2、final修饰的变量在定义时,必须赋值,并且以后不能再赋值。
final-- 什么时候用
1、因为案例的考虑,类的某个方法不允许修改。
2、类不会被其它的类继承。
3、某些变量值是固定不变的,比如圆周率3.1415926