java面向对象
成员变量和局部变量的区别:
A:在类中的位置不同
成员变量:在类中方法外
局部变量:在方法定义中或者方法声明上
B:在内存中的位置不同
成员变量:在堆内存
局部变量:在栈内存
C:生命周期不同
成员变量:随着对象的创建而存在,随着对象的消失而消失
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
D:初始化值不同
成员变量:有默认初始化值
局部变量:没有默认初始化值,必须定义,赋值,然后才能使用。
注意事项:
局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的是就近原则。
demo: |
class Varialbe { //成员变量 //int num = 10; int num; //0
public void show() { //int num2 = 20; //局部变量 //可能尚未初始化变量num2 //int num2; //没有默认值 int num2 = 20; System.out.println(num2);
//int num = 100; System.out.println(num); } }
class VariableDemo { public static void main(String[] args) { Varialbe v = new Varialbe();
System.out.println(v.num); //访问成员变量
v.show();
} } |
形式参数是类名:
基本类型:形式参数的改变不影响实际参数
引用类型:形式参数的改变直接影响实际参数
//形式参数是基本类型
class Demo {
public int sum(int a,int b) {
return a + b;
}
}
//形式参数是引用类型
class Student {
public void show() {
System.out.println("我爱学习");
}
}
class StudentDemo {
//如果你看到了一个方法的形式参数是一个类类型(引用类型),这里其实需要的是该类的对象。
public void method(Student s) { //调用的时候,把main方法中的s的地址传递到了这里 Student s = new Student();
s.show();
}
}
class ArgsTest {
public static void main(String[] args) {
//形式参数是基本类型的调用
Demo d = new Demo();
int result = d.sum(10,20);
System.out.println("result:"+result);
System.out.println("--------------");
//形式参数是引用类型的调用
//需求:我要调用StudentDemo类中的method()方法
StudentDemo sd = new StudentDemo();
//创建学生对象
Student s = new Student();
sd.method(s); //把s的地址给到了这里
}
}
匿名对象:
就是没有名字的对象
匿名对象的应用场景:
A:调用方法,仅仅只调用一次的时候。
注意:调用多次的时候,不适合。
那么,这种匿名调用有什么好处吗?
有,匿名对象调用完毕就是垃圾。可以被垃圾回收器回收。
B:匿名对象可以作为实际参数传递
demo: |
class Student { public void show() { System.out.println("我爱学习"); } }
class StudentDemo { public void method(Student s) { s.show(); } }
class NoNameDemo { public static void main(String[] args) { //带名字的调用 Student s = new Student(); s.show(); s.show(); System.out.println("--------------");
//匿名对象 //new Student(); //匿名对象调用方法 new Student().show(); new Student().show(); //这里其实是重新创建了一个新的对象 System.out.println("--------------");
//匿名对象作为实际参数传递 StudentDemo sd = new StudentDemo(); //Student ss = new Student(); //sd.method(ss); //这里的s是一个实际参数 //匿名对象 sd.method(new Student());
//在来一个 new StudentDemo().method(new Student()); } } |
封装的概述:
是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
好处:
隐藏实现细节,提供公共的访问方式
提高了代码的复用性
提高安全性。
封装原则:
将不需要对外提供的内容都隐藏起来。
把属性隐藏,提供公共方法对其访问。
demo: 定义一个学生类: 成员变量:name,age 成员方法:show()方法
我们在使用这个案例的过程中,发现了一个问题: 通过对象去给成员变量赋值,可以赋值一些非法的数据。 这是不合理的。 应该是这个样子的:在赋值之前,先对数据进行判断。 判断到底在哪里做比较合适呢? StudentDemo类是一个测试类,测试类一般只创建对象,调用方法。 所以,这个判断应该定义在Student类中。 而我们在成员变量的位置可不可以进行数据判断呢? 是不可以的,因为做数据校验,必须要依靠一些逻辑语句。 逻辑语句是应该定义在方法中的,所以,我们最终决定在Student类中提供一个方法 来对数据进行校验。
按照我们前面的分析,我们给出了一个方法进行校验。 但是呢,它偏偏不调用方法来赋值,还是直接赋值了, 这样我们的方法就没有起到作用。 我就应该要求你必须使用我的方法,而不能直接调用成员变量赋值。 怎么去强制要求不能直接使用成员变量呢? 针对这种情况,Java就提供了一个关键字 private
private:私有的。可以修饰成员变量和成员方法。 注意:被private修饰的成员只能在本类中访问。
|
class Student { //姓名 String name; //年龄 private int age;
//写一个方法对数据进行校验 /* 返回值类型:void 参数列表:int a */ public void setAge(int a) { if(a < 0 || age > 120) { System.out.println("你给的年龄有问题"); }else { age = a; } }
//show()方法,显示所有成员变量值 public void show() { System.out.println("姓名:"+name); System.out.println("年龄:"+age); } }
class StudentDemo { public static void main(String[] args) { //创建学生对象 Student s = new Student(); s.show(); System.out.println("--------------");
//给成员变量赋值 s.name = "林青霞"; //s.age = 27; s.setAge(27); s.show(); System.out.println("--------------");
//给age赋值 //s.age = -27; //这个数据是不合理的 //通过方法给值 s.setAge(-27); s.show(); System.out.println("--------------"); } } |
private关键字:
是一个权限修饰符。
可以修饰成员(成员变量和成员方法)
被private修饰的成员只在本类中才能访问。
private最常见的应用:
把成员变量用private修饰
提供对应的getXxx()/setXxx()方法
demo: 封装和private的应用: A:把成员变量用private修饰 B:提高对应的getXxx()和setXxx()方法
|
//定义学生类 class Student { //姓名 private String name; //年龄 private int age;
//姓名获取值 public String getName() { return name; }
//姓名设置值 public void setName(String n) { name = n; }
//年龄获取值 public int getAge() { return age; }
//年龄赋值 public void setAge(int a) { age = a; } }
//测试类 class StudentTest { public static void main(String[] args) { //创建学生对象 Student s = new Student();
//使用成员变量 //错误:被私有修饰了,外界不能直接访问了 //System.out.println(s.name+"---"+s.age); System.out.println(s.getName()+"---"+s.getAge());
//给成员变量赋值 //s.name = "林青霞"; //s.age = 27; //通过方法给赋值 s.setName("林青霞"); s.setAge(27); System.out.println(s.getName()+"---"+s.getAge()); } } |
this关键字:
this:是当前类的对象引用。简单的记,它就代表当前类的一个对象。
注意:谁调用这个方法,在该方法内部的this就代表谁。
this的场景:
解决局部变量隐藏成员变量
Demo: |
//定义学生类 class Student { //姓名 private String name; //年龄 private int age;
//姓名获取值 public String getName() { return name; }
//姓名设置值 public void setName(String name) { //name = "林青霞"; //name = name; //变量的使用规则:就近原则 //这里是类名,目前还没有说过类似的用法,所以这个是有问题的 //这里的调用只能通过对象名 //这个对象如果存在,它应该代表的是Student的一个对象。 //那么,谁能够代表当前类的对象呢? java就提供了一个关键字 this //Student.name = name; this.name = name; }
//年龄获取值 public int getAge() { return age; }
//年龄赋值 public void setAge(int age) { this.age = age; } }
//测试类 class StudentTest { public static void main(String[] args) { //创建学生对象 Student s = new Student();
//给成员变量赋值 s.setName("林青霞"); s.setAge(27); //获取数据 System.out.println(s.getName()+"---"+s.getAge()); } } |
构造方法概述和格式:
A:如果我们没有给出构造方法,系统将自动提供一个无参构造方法。
B:如果我们给出了构造方法,系统将不再提供默认的无参构造方法。
注意:这个时候,如果我们还想使用无参构造方法,就必须自己给出。建议永远自己给出无参构造方法
给成员变量赋值有两种方式:
A:setXxx()
B:构造方法
demo: |
class Student { private String name; private int age;
public Student() { //System.out.println("我给了,你还给不"); System.out.println("这是无参构造方法"); }
//构造方法的重载格式 public Student(String name) { System.out.println("这是带一个String类型的构造方法"); this.name = name; }
public Student(int age) { System.out.println("这是带一个int类型的构造方法"); this.age = age; }
public Student(String name,int age) { System.out.println("这是一个带多个参数的构造方法"); this.name = name; this.age = age; }
public void show() { System.out.println(name+"---"+age); } }
class ConstructDemo2 { public static void main(String[] args) { //创建对象 Student s = new Student(); s.show(); System.out.println("-------------");
//创建对象2 Student s2 = new Student("林青霞"); s2.show(); System.out.println("-------------");
//创建对象3 Student s3 = new Student(27); s3.show(); System.out.println("-------------");
//创建对象4 Student s4 = new Student("林青霞",27); s4.show(); } } |
类初始化的过程:
static关键字:
static的特点:(它可以修饰成员变量,还可以修饰成员方法)
A:随着类的加载而加载
回想main方法。
B:优先于对象存在
C:被类的所有对象共享
举例:咱们班级的学生应该共用同一个班级编号。
其实这个特点也是在告诉我们什么时候使用静态?
如果某个成员变量是被所有对象共享的,那么它就应该定义为静态的。
举例:
饮水机(用静态修饰)
水杯(不能用静态修饰)
D:可以通过类名调用
其实它本身也可以通过对象名调用。
推荐使用类名调用。
静态修饰的内容一般我们称其为:与类相关的,类成员
demo: static关键字注意事项 A:在静态方法中是没有this关键字的 如何理解呢? 静态是随着类的加载而加载,this是随着对象的创建而存在。 静态比对象先存在。 B:静态方法只能访问静态的成员变量和静态的成员方法 静态方法: 成员变量:只能访问静态变量 成员方法:只能访问静态成员方法 非静态方法: 成员变量:可以是静态的,也可以是非静态的 成员方法:可是是静态的成员方法,也可以是非静态的成员方法。 简单记: 静态只能访问静态。
|
class Teacher { public int num = 10; public static int num2 = 20;
public void show() { System.out.println(num); //隐含的告诉你访问的是成员变量 System.out.println(this.num); //明确的告诉你访问的是成员变量 System.out.println(num2);
//function(); //function2(); }
public static void method() { //无法从静态上下文中引用非静态 变量 num //System.out.println(num); System.out.println(num2);
//无法从静态上下文中引用非静态 方法 function() //function(); function2(); }
public void function() {
}
public static void function2() {
} }
class TeacherDemo { public static void main(String[] args) { //创建对象 Teacher t = new Teacher(); t.show(); System.out.println("------------"); t.method(); } } |
main方法的格式详解:
main方法的格式讲解:
public static void main(String[] args) {...}
public:公共的,访问权限是最大的。由于main方法是被jvm调用,所以权限要够大。
static:静态的,不需要创建对象,通过类名就可以。方便jvm的调用。
void:因为我们曾经说过,方法的返回值是返回给调用者,而main方法是被jvm调用。你返回内容给jvm没有意义。
main:是一个常见的方法入口。我见过的语言都是以main作为入口。
String[] args:这是一个字符串数组。值去哪里了?
这个东西到底有什么用啊?怎么给值啊?
这个东西早期是为了接收键盘录入的数据的。
格式是:
java MainDemo hello world java
demo: |
class MainDemo { public static void main(String[] args) { //System.out.println(args); //[Ljava.lang.String;@175078b //System.out.println(args.length); //0 //System.out.println(args[0]); //ArrayIndexOutOfBoundsException
//接收数据后 System.out.println(args); System.out.println(args.length); //System.out.println(args[0]); for(int x=0; x<args.length; x++) { System.out.println(args[x]); } } } |
帮助文档的制作和使用:
如何制作一个说明书呢?
A:写一个工具类
B:对这个类加入文档注释
怎么加呢?
加些什么东西呢?
C:用工具解析文档注释
javadoc工具
D:格式
javadoc -d 目录 -author -version ArrayTool.java
目录:就可以写一个文件夹的路径
制作帮助文档出错:
找不到可以文档化的公共或受保护的类:告诉我们类的权限不够
帮助文档的使用:
1:打开帮助文档
2:点击显示,找到索引,看到输入框
3:知道你要找谁?以Scanner举例
4:在输入框里面输入Scanner,然后回车
5:看包
java.lang包下的类不需要导入,其他的全部需要导入。
要导入:
java.util.Scanner
6:再简单的看看类的解释和说明,别忘了看看该类的版本
7:看类的结构
成员变量 字段摘要
构造方法 构造方法摘要
成员方法 方法摘要
8:学习构造方法
A:有构造方法 就创建对象
B:没有构造方法 成员可能都是静态的
9:看成员方法
A:左边
是否静态:如果静态,可以通过类名调用
返回值类型:人家返回什么,你就用什么接收。
B:右边
看方法名:方法名称不要写错
参数列表:人家要什么,你就给什么;人家要几个,你就给几个
获取1到100之间的随机数
class MathDemo {
public static void main(String[] args) {
//获取一个随机数
//double d = Math.random();
//System.out.println(d);
//需求:我要获取一个1-100之间的随机数,肿么办?
for(int x=0; x<100; x++) {
int number = (int)(Math.random()*100)+1;
System.out.println(number);
}
}
}
java中的Math类:
demo: 猜数字小游戏(数据在1-100之间) 分析: A:程序产生一个随机数。(被猜的) B:键盘录入数据。(你猜的) C:把你猜的和被猜的进行比较 a:大了 b:小了 c:猜中了 D:给出多次猜的机会,猜中就结束。 while()循环,猜中就break
|
class GuessNumber { public static void main(String[] args) { //程序产生一个随机数。(被猜的) int number = (int)(Math.random()*100)+1; //System.out.println(number);
//给出多次猜的机会,猜中就结束。 while(true) { //键盘录入数据。(你猜的) Scanner sc = new Scanner(System.in); System.out.println("请输入你要猜的数据(1-100):"); int guessNumber = sc.nextInt();
//把你猜的和被猜的进行比较 if(guessNumber > number) { System.out.println("你猜的数据"+guessNumber+"大了"); }else if(guessNumber < number) { System.out.println("你猜的数据"+guessNumber+"小了"); }else { System.out.println("恭喜你,猜中了"); break; } } } } |
代码块:
在Java中,使用{}括起来的代码被称为代码块
代码块:在Java中,使用{}括起来的代码被称为代码块。
根据其位置和声明的不同,可以分为
局部代码块:局部位置,用于限定变量的生命周期。
构造代码块:在类中的成员位置,用{}括起来的代码。每次调用构造方法执行前,都会先执行构造代码块。
作用:可以把多个构造方法中的共同代码放到一起,对对象进行初始化。
静态代码块:在类中的成员位置,用{}括起来的代码,只不过它用static修饰了。
作用:一般是对类进行初始化。
demo: |
class Code { static { int a = 1000; System.out.println(a); }
//构造代码块 { int x = 100; System.out.println(x); }
//构造方法 public Code(){ System.out.println("code"); }
//构造方法 public Code(int a){ System.out.println("code"); }
//构造代码块 { int y = 200; System.out.println(y); }
//静态代码块 static { int b = 2000; System.out.println(b); } }
class CodeDemo { public static void main(String[] args) { //局部代码块 { int x = 10; System.out.println(x); } //找不到符号 //System.out.println(x); { int y = 20; System.out.println(y); } System.out.println("---------------");
Code c = new Code(); System.out.println("---------------"); Code c2 = new Code(); System.out.println("---------------"); Code c3 = new Code(1); } } |
/* 写程序的执行结果。
我很伤心 我是main方法 Student 静态代码块 Student 构造代码块 Student 构造方法 Student 构造代码块 Student 构造方法 */ class Student { static { System.out.println("Student 静态代码块"); }
{ System.out.println("Student 构造代码块"); }
public Student() { System.out.println("Student 构造方法"); } }
class StudentDemo { static { System.out.println("我很伤心"); }
public static void main(String[] args) { System.out.println("我是main方法");
Student s1 = new Student(); Student s2 = new Student(); } } |
java中的继承:
继承概述:
把多个类中相同的内容给提取出来定义到一个类中。
如何实现继承呢?
Java提供了关键字:extends
格式:
class 子类名 extends 父类名 {}
好处:
A:提高了代码的复用性
B:提高了代码的维护性
C:让类与类之间产生了关系,是多态的前提
类与类产生了关系,其实也是继承的一个弊端:
类的耦合性增强了。
开发的原则:低耦合,高内聚。
耦合:类与类的关系
内聚:就是自己完成某件事情的能力
Demo: |
//使用继承前 /* class Student { public void eat() { System.out.println("吃饭"); }
public void sleep() { System.out.println("睡觉"); } }
class Teacher { public void eat() { System.out.println("吃饭"); }
public void sleep() { System.out.println("睡觉"); } } */
//使用继承后 class Person { public void eat() { System.out.println("吃饭"); }
public void sleep() { System.out.println("睡觉"); } }
class Student extends Person {}
class Teacher extends Person {}
class ExtendsDemo { public static void main(String[] args) { Student s = new Student(); s.eat(); s.sleep(); System.out.println("-------------");
Teacher t = new Teacher(); t.eat(); t.sleep(); } } |
Java中继承的特点:
A:Java只支持单继承,不支持多继承。
有些语言是支持多继承,格式:extends 类1,类2,...
B:Java支持多层继承(继承体系)
Demo: |
class GrandFather { public void show() { System.out.println("我是爷爷"); } }
class Father extends GrandFather { public void method(){ System.out.println("我是老子"); } }
class Son extends Father {}
class ExtendsDemo2 { public static void main(String[] args) { Son s = new Son(); s.method(); //使用父亲的 s.show(); //使用爷爷的 } } |
继承的注意事项:
A:子类只能继承父类所有非私有的成员(成员方法和成员变量)
B:子类不能继承父类的构造方法,但是可以通过super(马上讲)关键字去访问父类构造方法。
C:不要为了部分功能而去继承
class A {
public void show1(){}
public void show2(){}
}
class B {
public void show2(){}
public void show3(){}
}
//我们发现B类中出现了和A类一样的show2()方法,所以,我们就用继承来体现
class B extends A {
public void show3(){}
}
这样其实不好,因为这样你不但有了show2(),还多了show1()。
有可能show1()不是你想要的。
那么,我们什么时候考虑使用继承呢?
继承其实体现的是一种关系:"is a"。
Person
Student
Teacher
水果
苹果
香蕉
橘子
采用假设法。
如果有两个类A,B。只有他们符合A是B的一种,或者B是A的一种,就可以考虑使用继承。
Demo: |
class Father { private int num = 10; public int num2 = 20;
//私有方法,子类不能继承 private void method() { System.out.println(num); System.out.println(num2); }
public void show() { System.out.println(num); System.out.println(num2); } }
class Son extends Father { public void function() { //num可以在Father中访问private //System.out.println(num); //子类不能继承父类的私有成员变量 System.out.println(num2); } }
class ExtendsDemo3 { public static void main(String[] args) { // 创建对象 Son s = new Son(); //s.method(); //子类不能继承父类的私有成员方法 s.show(); s.function(); } } |
继承中成员变量的关系:
类的组成:
成员变量:
构造方法:
成员方法:
而现在我们又讲解了继承,所以,我们就应该来考虑一下,类的组成部分的各自关系。
继承中成员变量的关系:
A:子类中的成员变量和父类中的成员变量名称不一样,这个太简单。
B:子类中的成员变量和父类中的成员变量名称一样,这个怎么玩呢?
在子类方法中访问一个变量的查找顺序:
a:在子类方法的局部范围找,有就使用
b:在子类的成员范围找,有就使用
c:在父类的成员范围找,有就使用
d:如果还找不到,就报错。
demo: |
class Father { public int num = 10;
public void method() { int num = 50; } }
class Son extends Father { public int num2 = 20; public int num = 30;
public void show() { int num = 40; System.out.println(num); System.out.println(num2); // 找不到符号 System.out.println(num3); } }
class ExtendsDemo4 { public static void main(String[] args) { //创建对象 Son s = new Son(); s.show(); } } |
this和super的区别:
引入
问题是:
我不仅仅要输出局部范围的num,还要输出本类成员范围的num。怎么办呢?
我还想要输出父类成员范围的num。怎么办呢?
如果有一个东西和this相似,但是可以直接访问父类的数据就好了。
恭喜你,这个关键字是存在的:super。
this和super的区别?
分别是什么呢?
this代表本类对应的引用。
super代表父类存储空间的标识(可以理解为父类引用,可以操作父类的成员)
怎么用呢?
A:调用成员变量
this.成员变量 调用本类的成员变量
super.成员变量 调用父类的成员变量
B:调用构造方法
this(...) 调用本类的构造方法
super(...) 调用父类的构造方法
C:调用成员方法
this.成员方法 调用本类的成员方法
super.成员方法 调用父类的成员方法
demo: |
class Father { public int num = 10; }
class Son extends Father { public int num = 20;
public void show() { int num = 30; System.out.println(num); System.out.println(this.num); System.out.println(super.num); } }
class ExtendsDemo5 { public static void main(String[] args) { Son s = new Son(); s.show(); } } |
继承中构造方法的关系:
A:子类中所有的构造方法默认都会访问父类中空参数的构造方法
B:为什么呢?
因为子类会继承父类中的数据,可能还会使用父类的数据。
所以,子类初始化之前,一定要先完成父类数据的初始化。
注意:子类每一个构造方法的第一条语句默认都是:super();
demo: |
class Father { int age;
public Father() { System.out.println("Father的无参构造方法"); }
public Father(String name) { System.out.println("Father的带参构造方法"); } }
class Son extends Father { public Son() { //super(); System.out.println("Son的无参构造方法"); }
public Son(String name) { //super(); System.out.println("Son的带参构造方法"); } }
class ExtendsDemo6 { public static void main(String[] args) { //创建对象 Son s = new Son(); System.out.println("------------"); Son s2 = new Son("林青霞"); } } |
方法的重写:
子类中出现了和父类中方法的声明一模一样的方法声明,也被成为方法的覆盖,方法重写。
方法重载:
本类中出现的方法名一样,参数列表不同的方法。与返回值无关。
子类对象调用方法的时候:
先找子类本身,再找父类。
方法重写的应用:
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。
这样,即沿袭了父类的功能,又定义了子类特有的内容。
demo: |
class Phone { public void call(String name) { System.out.println("给"+name+"打电话"); } }
class NewPhone extends Phone { public void call(String name) { //System.out.println("给"+name+"打电话"); super.call(name); System.out.println("可以听天气预报了"); } }
class ExtendsDemo9 { public static void main(String[] args) { NewPhone np = new NewPhone(); np.call("林青霞"); } } |
方法重写的注意事项
A:父类中私有方法不能被重写
因为父类私有方法子类根本就无法继承
B:子类重写父类方法时,访问权限不能更低
最好就一致
C:父类静态方法,子类也必须通过静态方法进行重写
其实这个算不上方法重写,但是现象确实如此
demo: |
class Father { //private void show() {}
/* public void show() { System.out.println("show Father"); } */
void show() { System.out.println("show Father"); } /* public static void method() {
} */
public void method() {
} }
class Son extends Father { //private void show() {}
/* public void show() { System.out.println("show Son"); } */
public void show() { System.out.println("show Son"); }
public static void method() {
}
/* public void method() {
} */ }
class ExtendsDemo10 { public static void main(String[] args) { Son s = new Son(); s.show(); } } |
demo: 1:方法重写和方法重载的区别?方法重载能改变返回值类型吗?
方法重写: 在子类中,出现和父类中一模一样的方法声明的现象。
方法重载: 同一个类中,出现的方法名相同,参数列表不同的现象。
方法重载能改变返回值类型,因为它和返回值类型无关。
Override:方法重写 Overload:方法重载
|
demo: 2:this关键字和super关键字分别代表什么?以及他们各自的使用场景和作用。
this:代表当前类的对象引用 super:代表父类存储空间的标识。(可以理解为父类的引用,通过这个东西可以访问父类的成员)
场景: 成员变量: this.成员变量 super.成员变量 构造方法: this(...) super(...) 成员方法: this.成员方法
|
demo: 学生案例和老师案例讲解
学生: 成员变量;姓名,年龄 构造方法:无参,带参 成员方法:getXxx()/setXxx() 老师: 成员变量;姓名,年龄 构造方法:无参,带参 成员方法:getXxx()/setXxx()
看上面两个类的成员,发现了很多相同的东西,所以我们就考虑抽取一个共性的类: 人: 成员变量;姓名,年龄 构造方法:无参,带参 成员方法:getXxx()/setXxx()
学生 继承 人 老师 继承 人
|
//定义人类 class Person { //姓名 private String name; //年龄 private int age;
public Person() { }
public Person(String name,int age) { //"林青霞",27 this.name = name; this.age = 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; } }
//定义学生类 class Student extends Person { public Student() {}
public Student(String name,int age) { //"林青霞",27 //this.name = name; //this.age = age; super(name,age); } }
//定义老师类 class Teacher extends Person {
}
class ExtendsTest4 { public static void main(String[] args) { //创建学生对象并测试 //方式1 Student s1 = new Student(); s1.setName("林青霞"); s1.setAge(27); System.out.println(s1.getName()+"---"+s1.getAge());
//方式2 Student s2 = new Student("林青霞",27); System.out.println(s2.getName()+"---"+s2.getAge());
//补齐老师类中的代码并进行测试。 } } |
final关键字:
final关键字是最终的意思,可以修饰类,成员变量,成员方法。
修饰类,类不能被继承
修饰变量,变量就变成了常量,只能被赋值一次
修饰方法,方法不能被重写
常量:
A:字面值常量
"hello",10,true
B:自定义常量
final int x = 10;
demo: |
class Fu { public int num = 10; public final int num2 = 20;
/* public final void show() {
} */ }
class Zi extends Fu { // Zi中的show()无法覆盖Fu中的show() public void show() { num = 100; System.out.println(num);
//无法为最终变量num2分配值 //num2 = 200; System.out.println(num2); } }
class FinalDemo { public static void main(String[] args) { Zi z = new Zi(); z.show(); } } |
final修饰局部变量的问题
基本类型:基本类型的值不能发生改变。
引用类型:引用类型的地址值不能发生改变,但是,该对象的堆内存的值是可以改变的。
demo: |
class Student { int age = 10; }
class FinalTest { public static void main(String[] args) { //局部变量是基本数据类型 int x = 10; x = 100; System.out.println(x); final int y = 10; //无法为最终变量y分配值 //y = 100; System.out.println(y); System.out.println("--------------");
//局部变量是引用数据类型 Student s = new Student(); System.out.println(s.age); s.age = 100; System.out.println(s.age); System.out.println("--------------");
final Student ss = new Student(); System.out.println(ss.age); ss.age = 100; System.out.println(ss.age);
//重新分配内存空间 //无法为最终变量ss分配值 ss = new Student(); } } |
final修饰变量的初始化时机
A:被final修饰的变量只能赋值一次。
B:在构造方法完毕前。(非静态的常量)
demo: |
class Demo { //int num = 10; //final int num2 = 20;
int num; final int num2;
{ //num2 = 10; }
public Demo() { num = 100; //无法为最终变量num2分配值 num2 = 200; } }
class FinalTest2 { public static void main(String[] args) { Demo d = new Demo(); System.out.println(d.num); System.out.println(d.num2); } } |
多态:
多态:同一个对象(事物),在不同时刻体现出来的不同状态。
举例:
猫是猫,猫是动物。
水(液体,固体,气态)。
多态的前提:
A:要有继承关系。
B:要有方法重写。
其实没有也是可以的,但是如果没有这个就没有意义。
动物 d = new 猫();
d.show();
动物 d = new 狗();
d.show();
C:要有父类引用指向子类对象。
父 f = new 子();
用代码体现一下多态。
多态中的成员访问特点:
A:成员变量
编译看左边,运行看左边。
B:构造方法
创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
C:成员方法
编译看左边,运行看右边。
D:静态方法
编译看左边,运行看左边。
(静态和类相关,算不上重写,所以,访问还是左边的)
由于成员方法存在方法重写,所以它运行看右边。
demo: |
class Fu { public int num = 100;
public void show() { System.out.println("show Fu"); }
public static void function() { System.out.println("function Fu"); } }
class Zi extends Fu { public int num = 1000; public int num2 = 200;
public void show() { System.out.println("show Zi"); }
public void method() { System.out.println("method zi"); }
public static void function() { System.out.println("function Zi"); } }
class DuoTaiDemo { public static void main(String[] args) { //要有父类引用指向子类对象。 //父 f = new 子(); Fu f = new Zi(); System.out.println(f.num); //找不到符号 //System.out.println(f.num2);
f.show(); //找不到符号 //f.method(); f.function(); } } |
多态的好处:
A:提高了代码的维护性(继承保证)
B:提高了代码的扩展性(由多态保证)
Demo: |
class Animal { public void eat(){ System.out.println("eat"); }
public void sleep(){ System.out.println("sleep"); } }
class Dog extends Animal { public void eat(){ System.out.println("狗吃肉"); }
public void sleep(){ System.out.println("狗站着睡觉"); } }
class Cat extends Animal { public void eat() { System.out.println("猫吃鱼"); }
public void sleep() { System.out.println("猫趴着睡觉"); } }
class Pig extends Animal { public void eat() { System.out.println("猪吃白菜"); }
public void sleep() { System.out.println("猪侧着睡"); } }
//针对动物操作的工具类 class AnimalTool { private AnimalTool(){}
/* //调用猫的功能 public static void useCat(Cat c) { c.eat(); c.sleep(); }
//调用狗的功能 public static void useDog(Dog d) { d.eat(); d.sleep(); }
//调用猪的功能 public static void usePig(Pig p) { p.eat(); p.sleep(); } */ public static void useAnimal(Animal a) { a.eat(); a.sleep(); }
}
class DuoTaiDemo2 { public static void main(String[] args) { //我喜欢猫,就养了一只 Cat c = new Cat(); c.eat(); c.sleep();
//我很喜欢猫,所以,又养了一只 Cat c2 = new Cat(); c2.eat(); c2.sleep();
//我特别喜欢猫,又养了一只 Cat c3 = new Cat(); c3.eat(); c3.sleep(); //... System.out.println("--------------"); //问题来了,我养了很多只猫,每次创建对象是可以接受的 //但是呢?调用方法,你不觉得很相似吗?仅仅是对象名不一样。 //我们准备用方法改进 //调用方式改进版本 //useCat(c); //useCat(c2); //useCat(c3);
//AnimalTool.useCat(c); //AnimalTool.useCat(c2); //AnimalTool.useCat(c3);
AnimalTool.useAnimal(c); AnimalTool.useAnimal(c2); AnimalTool.useAnimal(c3); System.out.println("--------------");
//我喜欢狗 Dog d = new Dog(); Dog d2 = new Dog(); Dog d3 = new Dog(); //AnimalTool.useDog(d); //AnimalTool.useDog(d2); //AnimalTool.useDog(d3); AnimalTool.useAnimal(d); AnimalTool.useAnimal(d2); AnimalTool.useAnimal(d3); System.out.println("--------------");
//我喜欢宠物猪 //定义一个猪类,它要继承自动物,提供两个方法,并且还得在工具类中添加该类方法调用 Pig p = new Pig(); Pig p2 = new Pig(); Pig p3 = new Pig(); //AnimalTool.usePig(p); //AnimalTool.usePig(p2); //AnimalTool.usePig(p3); AnimalTool.useAnimal(p); AnimalTool.useAnimal(p2); AnimalTool.useAnimal(p3); System.out.println("--------------");
//我喜欢宠物狼,老虎,豹子... //定义对应的类,继承自动物,提供对应的方法重写,并在工具类添加方法调用 //前面几个必须写,我是没有意见的 //但是,工具类每次都改,麻烦不 //我就想,你能不能不改了 //太简单:把所有的动物都写上。问题是名字是什么呢?到底哪些需要被加入呢? //改用另一种解决方案。
}
/* //调用猫的功能 public static void useCat(Cat c) { c.eat(); c.sleep(); }
//调用狗的功能 public static void useDog(Dog d) { d.eat(); d.sleep(); } */ } |
多态的弊端:
不能使用子类的特有功能。
我就想使用子类的特有功能?行不行?
行。
怎么用呢?
A:创建子类对象调用方法即可。(可以,但是很多时候不合理。而且,太占内存了)
B:把父类的引用强制转换为子类的引用。(向下转型)
对象间的转型问题:
向上转型:
Fu f = new Zi();
向下转型:
Zi z = (Zi)f; //要求该f必须是能够转换为Zi的。
Demo: |
class Fu { public void show() { System.out.println("show fu"); } }
class Zi extends Fu { public void show() { System.out.println("show zi"); }
public void method() { System.out.println("method zi"); }
}
class DuoTaiDemo4 { public static void main(String[] args) { //测试 Fu f = new Zi(); f.show(); //f.method();
//创建子类对象 //Zi z = new Zi(); //z.show(); //z.method();
//你能够把子的对象赋值给父亲,那么我能不能把父的引用赋值给子的引用呢? //如果可以,但是如下 Zi z = (Zi)f; z.show(); z.method(); } } |
多态中的继承图解:
多态中对象变化的图解:
ClassCastException:类型转换异常
一般在多态的向下转型中容易出现
多态的案例:猫狗案例:
demo: |
class Animal { public void eat(){ System.out.println("吃饭"); } }
class Dog extends Animal { public void eat() { System.out.println("狗吃肉"); }
public void lookDoor() { System.out.println("狗看门"); } }
class Cat extends Animal { public void eat() { System.out.println("猫吃鱼"); }
public void playGame() { System.out.println("猫捉迷藏"); } }
class DuoTaiTest { public static void main(String[] args) { //定义为狗 Animal a = new Dog(); a.eat(); System.out.println("--------------"); //还原成狗 Dog d = (Dog)a; d.eat(); d.lookDoor(); System.out.println("--------------"); //变成猫 a = new Cat(); a.eat(); System.out.println("--------------"); //还原成猫 Cat c = (Cat)a; c.eat(); c.playGame(); System.out.println("--------------");
//演示错误的内容 //Dog dd = new Animal(); //Dog ddd = new Cat(); //ClassCastException //Dog dd = (Dog)a; } } |
demo: 南北方人饮食文化不同的案例 |
class Person { public void eat() { System.out.println("吃饭"); } }
class SouthPerson extends Person { public void eat() { System.out.println("炒菜,吃米饭"); }
public void jingShang() { System.out.println("经商"); } }
class NorthPerson extends Person { public void eat() { System.out.println("炖菜,吃馒头"); }
public void yanJiu() { System.out.println("研究"); } }
class DuoTaiTest2 { public static void main(String[] args) { //测试 //南方人 Person p = new SouthPerson(); p.eat(); System.out.println("-------------"); SouthPerson sp = (SouthPerson)p; sp.eat(); sp.jingShang(); System.out.println("-------------");
//北方人 p = new NorthPerson(); p.eat(); System.out.println("-------------"); NorthPerson np = (NorthPerson)p; np.eat(); np.yanJiu(); } } |
抽象类:
抽象类的概述:
动物不应该定义为具体的东西,而且动物中的吃,睡等也不应该是具体的。
我们把一个不是具体的功能称为抽象的功能,而一个类中如果有抽象的功能,该类必须是抽象类。
抽象类的特点:
A:抽象类和抽象方法必须用abstract关键字修饰
B:抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类
C:抽象类不能实例化
因为它不是具体的。
抽象类有构造方法,但是不能实例化?构造方法的作用是什么呢?
用于子类访问父类数据的初始化
D:抽象的子类
a:如果不想重写抽象方法,该子类是一个抽象类。
b:重写所有的抽象方法,这个时候子类是一个具体的类。
抽象类的实例化其实是靠具体的子类实现的。是多态的方式。
Animal a = new Cat();
demo: |
abstract class Animal { //抽象方法 //public abstract void eat(){} //空方法体,这个会报错。抽象方法不能有主体 public abstract void eat();
public Animal(){} }
//子类是抽象类 abstract class Dog extends Animal {}
//子类是具体类,重写抽象方法 class Cat extends Animal { public void eat() { System.out.println("猫吃鱼"); } }
class AbstractDemo { public static void main(String[] args) { //创建对象 //Animal是抽象的; 无法实例化 //Animal a = new Animal(); //通过多态的方式 Animal a = new Cat(); a.eat(); } } |
抽象类的成员特点:
成员变量:既可以是变量,也可以是常量。
构造方法:有。
用于子类访问父类数据的初始化。
成员方法:既可以是抽象的,也可以是非抽象的。
抽象类的成员方法特性:
A:抽象方法 强制要求子类做的事情。
B:非抽象方法 子类继承的事情,提高代码复用性。
Demo: |
abstract class Animal { public int num = 10; public final int num2 = 20;
public Animal() {}
public Animal(String name,int age){}
public abstract void show();
public void method() { System.out.println("method"); } }
class Dog extends Animal { public void show() { System.out.println("show Dog"); } }
class AbstractDemo2 { public static void main(String[] args) { //创建对象 Animal a = new Dog(); a.num = 100; System.out.println(a.num); //a.num2 = 200; System.out.println(a.num2); System.out.println("--------------"); a.show(); a.method(); } } |
猫狗案例
具体事物:猫,狗
共性:姓名,年龄,吃饭
分析:从具体到抽象
猫:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭(猫吃鱼)
狗:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭(狗吃肉)
因为有共性的内容,所以就提取了一个父类。动物。
但是又由于吃饭的内容不一样,所以吃饭的方法是抽象的,
而方法是抽象的类,类就必须定义为抽象类。
抽象动物类:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭();
实现:从抽象到具体
动物类:
成员变量:姓名,年龄
构造方法:无参,带参
成员方法:吃饭();
狗类:
继承自动物类
重写吃饭();
猫类:
继承自动物类
重写吃饭();
Demo: |
//定义抽象的动物类 abstract class Animal { //姓名 private String name; //年龄 private int age;
public Animal() {}
public Animal(String name,int age) { this.name = name; this.age = 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 abstract void eat(); }
//定义具体的狗类 class Dog extends Animal { public Dog() {}
public Dog(String name,int age) { super(name,age); }
public void eat() { System.out.println("狗吃肉"); } }
//定义具体的猫类 class Cat extends Animal { public Cat() {}
public Cat(String name,int age) { super(name,age); }
public void eat() { System.out.println("猫吃鱼"); } }
//测试类 class AbstractTest { public static void main(String[] args) { //测试狗类 //具体类用法 //方式1: Dog d = new Dog(); d.setName("旺财"); d.setAge(3); System.out.println(d.getName()+"---"+d.getAge()); d.eat(); //方式2: Dog d2 = new Dog("旺财",3); System.out.println(d2.getName()+"---"+d2.getAge()); d2.eat(); System.out.println("---------------------------");
Animal a = new Dog(); a.setName("旺财"); a.setAge(3); System.out.println(a.getName()+"---"+a.getAge()); a.eat();
Animal a2 = new Dog("旺财",3); System.out.println(a2.getName()+"---"+a2.getAge()); a2.eat();
} |
假如我们在开发一个系统时需要对员工类进行设计,员工包含3个属性:姓名、工号以及工资。
经理也是员工,除了含有员工的属性外,另为还有一个奖金属性。
请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问。
分析:
普通员工类
成员变量:姓名、工号以及工资。
成员方法:工作
经理类:
成员变量:姓名、工号以及工资,奖金属性
成员方法:工作
实现:
员工类:
普通员工类:
经理类:
Demo: |
//定义员工类 abstract class Employee { //姓名、工号以及工资 private String name; private String id; private int salary;
public Employee() {}
public Employee(String name,String id,int salary) { this.name = name; this.id = id; this.salary = salary; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public int getSalary() { return salary; }
public void setSalary(int salary) { this.salary = salary; }
//工作 public abstract void work(); }
//普通员工类 class Programmer extends Employee { public Programmer(){}
public Programmer(String name,String id,int salary) { super(name,id,salary); }
public void work() { System.out.println("按照需求写代码"); } }
//经理类 class Manager extends Employee { //奖金 private int money; //bonus 奖金
public Manager(){}
public Manager(String name,String id,int salary,int money) { super(name,id,salary); this.money = money; }
public void work() { System.out.println("跟客户谈需求"); }
public int getMoney() { return money; }
public void setMoney(int money) { this.money = money; } }
class AbstractTest4 { public static void main(String[] args) { //测试普通员工 Employee emp = new Programmer(); emp.setName("林青霞"); emp.setId("czbk001"); emp.setSalary(18000); System.out.println(emp.getName()+"---"+emp.getId()+"---"+emp.getSalary()); emp.work(); System.out.println("-------------"); emp = new Programmer("林青霞","czbk001",18000); System.out.println(emp.getName()+"---"+emp.getId()+"---"+emp.getSalary()); emp.work(); System.out.println("-------------");
/* emp = new Manager(); emp.setName("刘意"); emp.setId("czbk002"); emp.setSalary(8000); emp.setMoney(2000); */ //由于子类有特有的内容,所以我们用子类来测试 Manager m = new Manager(); m.setName("刘意"); m.setId("czbk002"); m.setSalary(8000); m.setMoney(2000); System.out.println(m.getName()+"---"+m.getId()+"---"+m.getSalary()+"---"+m.getMoney()); m.work(); System.out.println("-------------");
//通过构造方法赋值 m = new Manager("刘意","czbk002",8000,2000); System.out.println(m.getName()+"---"+m.getId()+"---"+m.getSalary()+"---"+m.getMoney()); m.work(); } } |
一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
A:可以。
B:不让创建对象。
abstract不能和哪些关键字共存?
private 冲突
final 冲突
static 无意义
接口:
接口的特点:
A:接口用关键字interface表示
interface 接口名 {}
B:类实现接口用implements表示
class 类名 implements 接口名 {}
C:接口不能实例化
那么,接口如何实例化呢?
按照多态的方式来实例化。
D:接口的子类
a:可以是抽象类。但是意义不大。
b:可以是具体类。要重写接口中的所有抽象方法。(推荐方案)
由此可见:
A:具体类多态(几乎没有)
B:抽象类多态(常用)
C:接口多态(最常用)
demo: |
//定义动物培训接口 interface AnimalTrain { public abstract void jump(); }
//抽象类实现接口 abstract class Dog implements AnimalTrain { }
//具体类实现接口 class Cat implements AnimalTrain { public void jump() { System.out.println("猫可以跳高了"); } }
class InterfaceDemo { public static void main(String[] args) { //AnimalTrain是抽象的; 无法实例化 //AnimalTrain at = new AnimalTrain(); //at.jump();
AnimalTrain at = new Cat(); at.jump(); } } |
接口成员特点
成员变量;只能是常量,并且是静态的。
默认修饰符:public static final
建议:自己手动给出。
构造方法:接口没有构造方法。
成员方法:只能是抽象方法。
默认修饰符:public abstract
建议:自己手动给出。
所有的类都默认继承自一个类:Object。
类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。
demo: |
interface Inter { public int num = 10; public final int num2 = 20; public static final int num3 = 30;
//错误: 需要<标识符> //public Inter() {}
//接口方法不能带有主体 //public void show() {}
//abstract void show(); //默认public public void show(); //默认abstract }
//接口名+Impl这种格式是接口的实现类格式 /* class InterImpl implements Inter { public InterImpl() { super(); } } */
class InterImpl extends Object implements Inter { public InterImpl() { super(); }
public void show() {} }
//测试类 class InterfaceDemo2 { public static void main(String[] args) { //创建对象 Inter i = new InterImpl(); System.out.println(i.num); System.out.println(i.num2); //i.num = 100; //i.num2 = 200; //System.out.println(i.num); //无法为最终变量num分配值 //System.out.println(i.num2);//无法为最终变量num2分配值 System.out.println(Inter.num); System.out.println(Inter.num2); System.out.println("--------------"); } } |
类与类:
继承关系,只能单继承,可以多层继承。
类与接口:
实现关系,可以单实现,也可以多实现。
并且还可以在继承一个类的同时实现多个接口。
接口与接口:
继承关系,可以单继承,也可以多继承。
demo: |
interface Father { public abstract void show(); }
interface Mother { public abstract void show2(); }
interface Sister extends Father,Mother {
}
//class Son implements Father,Mother //多实现 class Son extends Object implements Father,Mother { public void show() { System.out.println("show son"); }
public void show2() { System.out.println("show2 son"); } }
class InterfaceDemo3 { public static void main(String[] args) { //创建对象 Father f = new Son(); f.show(); //f.show2(); //报错
Mother m = new Son(); //m.show(); //报错 m.show2(); } } |
demo: 猫狗案例,加入跳高的额外功能
分析:从具体到抽象 猫: 姓名,年龄 吃饭,睡觉 狗: 姓名,年龄 吃饭,睡觉
由于有共性功能,所以,我们抽取出一个父类: 动物: 姓名,年龄 吃饭(); 睡觉(){}
猫:继承自动物 狗:继承自动物
跳高的额外功能是一个新的扩展功能,所以我们要定义一个接口 接口: 跳高
部分猫:实现跳高 部分狗:实现跳高 实现; 从抽象到具体
使用: 使用具体类
|
//定义跳高接口 interface Jumpping { //跳高功能 public abstract void jump(); }
//定义抽象类 abstract class Animal { //姓名 private String name; //年龄 private int age;
public Animal() {}
public Animal(String name,int age) { this.name = name; this.age = 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 abstract void eat();
//睡觉(){} public void sleep() { System.out.println("睡觉觉了"); } }
//具体猫类 class Cat extends Animal { public Cat(){}
public Cat(String name,int age) { super(name,age); }
public void eat() { System.out.println("猫吃鱼"); } }
//具体狗类 class Dog extends Animal { public Dog(){}
public Dog(String name,int age) { super(name,age); }
public void eat() { System.out.println("狗吃肉"); } }
//有跳高功能的猫 class JumpCat extends Cat implements Jumpping { public JumpCat() {}
public JumpCat(String name,int age) { super(name,age); }
public void jump() { System.out.println("跳高猫"); } }
//有跳高功能的狗 class JumpDog extends Dog implements Jumpping { public JumpDog() {}
public JumpDog(String name,int age) { super(name,age); }
public void jump() { System.out.println("跳高狗"); } }
class InterfaceTest { public static void main(String[] args) { //定义跳高猫并测试 JumpCat jc = new JumpCat(); jc.setName("哆啦A梦"); jc.setAge(3); System.out.println(jc.getName()+"---"+jc.getAge()); jc.eat(); jc.sleep(); jc.jump(); System.out.println("-----------------");
JumpCat jc2 = new JumpCat("加菲猫",2); System.out.println(jc2.getName()+"---"+jc2.getAge()); jc2.eat(); jc2.sleep(); jc2.jump();
//定义跳高狗并进行测试的事情自己完成。 } } |
demo: 老师和学生案例,加入抽烟的额外功能
分析:从具体到抽象 老师:姓名,年龄,吃饭,睡觉 学生:姓名,年龄,吃饭,睡觉
由于有共性功能,我们提取出一个父类,人类。
人类: 姓名,年龄 吃饭(); 睡觉(){}
抽烟的额外功能不是人或者老师,或者学生一开始就应该具备的,所以,我们把它定义为接口
抽烟接口。
部分老师抽烟:实现抽烟接口 部分学生抽烟:实现抽烟接口
实现:从抽象到具体
使用:具体
|
//定义抽烟接口 interface Smoking { //抽烟的抽象方法 public abstract void smoke(); }
//定义抽象人类 abstract class Person { //姓名 private String name; //年龄 private int age;
public Person() {}
public Person(String name,int age) { this.name = name; this.age = 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 abstract void eat();
//睡觉(){} public void sleep() { System.out.println("睡觉觉了"); } }
//具体老师类 class Teacher extends Person { public Teacher() {}
public Teacher(String name,int age) { super(name,age); }
public void eat() { System.out.println("吃大白菜"); } }
//具体学生类 class Student extends Person { public Student() {}
public Student(String name,int age) { super(name,age); }
public void eat() { System.out.println("吃红烧肉"); } }
//抽烟的老师 class SmokingTeacher extends Teacher implements Smoking { public SmokingTeacher() {}
public SmokingTeacher(String name,int age) { super(name,age); }
public void smoke() { System.out.println("抽烟的老师"); } }
//抽烟的学生 class SmokingStudent extends Student implements Smoking { public SmokingStudent() {}
public SmokingStudent(String name,int age) { super(name,age); }
public void smoke() { System.out.println("抽烟的学生"); } }
class InterfaceTest2 { public static void main(String[] args) { //测试学生 SmokingStudent ss = new SmokingStudent(); ss.setName("林青霞"); ss.setAge(27); System.out.println(ss.getName()+"---"+ss.getAge()); ss.eat(); ss.sleep(); ss.smoke(); System.out.println("-------------------");
SmokingStudent ss2 = new SmokingStudent("刘意",30); System.out.println(ss2.getName()+"---"+ss2.getAge()); ss2.eat(); ss2.sleep(); ss2.smoke();
//测试老师留给自己练习 } } |
抽象类和接口的区别:
A:成员区别
抽象类:
成员变量:可以变量,也可以常量
构造方法:有
成员方法:可以抽象,也可以非抽象
接口:
成员变量:只可以常量
成员方法:只可以抽象
B:关系区别
类与类
继承,单继承
类与接口
实现,单实现,多实现
接口与接口
继承,单继承,多继承
C:设计理念区别
抽象类 被继承体现的是:"is a"的关系。抽象类中定义的是该继承体系的共性功能。
接口 被实现体现的是:"like a"的关系。接口中定义的是该继承体系的扩展功能。
形式参数和返回值的问题
形式参数:
基本类型
引用类型
类名:需要的是该类的对象
抽象类:需要的是该抽象的类子类对象
接口:需要的是该接口的实现类对象
Demo: 类名:需要的是该类的对象 |
class Student { public void study() { System.out.println("Good Good Study,Day Day Up"); } }
class StudentDemo { public void method(Student s) { //ss; ss = new Student(); Student s = new Student(); s.study(); } }
class StudentTest { public static void main(String[] args) { //需求:我要测试Student类的study()方法 Student s = new Student(); s.study(); System.out.println("----------------");
//需求2:我要测试StudentDemo类中的method()方法 StudentDemo sd = new StudentDemo(); Student ss = new Student(); sd.method(ss); System.out.println("----------------");
//匿名对象用法 new StudentDemo().method(new Student()); } } |
demo: 抽象类:需要的是该抽象的类子类对象 |
abstract class Person { public abstract void study(); }
class PersonDemo { public void method(Person p) {//p; p = new Student(); Person p = new Student(); //多态 p.study(); } }
//定义一个具体的学生类 class Student extends Person { public void study() { System.out.println("Good Good Study,Day Day Up"); } }
class PersonTest { public static void main(String[] args) { //目前是没有办法的使用的 //因为抽象类没有对应的具体类 //那么,我们就应该先定义一个具体类 //需求:我要使用PersonDemo类中的method()方法 PersonDemo pd = new PersonDemo(); Person p = new Student(); pd.method(p); } } |
Demo: 接口:需要的是该接口的实现类对象 |
interface Love { public abstract void love(); }
class LoveDemo { public void method(Love l) { //l; l = new Teacher(); Love l = new Teacher(); 多态 l.love(); } }
//定义具体类实现接口 class Teacher implements Love { public void love() { System.out.println("老师爱学生,爱Java"); } }
class TeacherTest { public static void main(String[] args) { //需求:我要测试LoveDemo类中的love()方法 LoveDemo ld = new LoveDemo(); Love l = new Teacher(); ld.method(l); } } |
返回值类型
基本类型:
引用类型:
类:返回的是该类的对象
抽象类:返回的是该抽象类的子类对象
接口:返回的是该接口的实现类的对象
Demo: 类:返回的是该类的对象 |
class Student { public void study() { System.out.println("Good Good Study,Day Day Up"); } }
class StudentDemo { public Student getStudent() { //Student s = new Student(); //Student ss = s;
//Student s = new Student(); //return s; return new Student(); } }
class StudentTest2 { public static void main(String[] args) { //需求:我要使用Student类中的study()方法 //但是,这一次我的要求是,不要直接创建Student的对象 //让你使用StudentDemo帮你创建对象 StudentDemo sd = new StudentDemo(); Student s = sd.getStudent(); //new Student(); Student s = new Student(); s.study(); } } |
Demo: 抽象类:返回的是该抽象类的子类对象 |
abstract class Person { public abstract void study(); }
class PersonDemo { public Person getPerson() { //Person p = new Student(); //return p;
return new Student(); } }
class Student extends Person { public void study() { System.out.println("Good Good Study,Day Day Up"); } }
class PersonTest2 { public static void main(String[] args) { //需求:我要测试Person类中的study()方法 PersonDemo pd = new PersonDemo(); Person p = pd.getPerson(); //new Student(); Person p = new Student(); 多态 p.study(); } } |
demo: 接口:返回的是该接口的实现类的对象 |
interface Love { public abstract void love(); }
class LoveDemo { public Love getLove() { //Love l = new Teacher(); //return l;
return new Teacher(); } }
//定义具体类实现接口 class Teacher implements Love { public void love() { System.out.println("老师爱学生,爱Java"); } }
class TeacherTest2 { public static void main(String[] args) { //如何测试呢? LoveDemo ld = new LoveDemo(); Love l = ld.getLove(); //new Teacher(); Love l = new Teacher(); 多态 l.love(); } } |
链式编程:
每次调用完毕方法后,返回的是一个对象。
Demo: |
class Student { public void study() { System.out.println("Good Good Study,Day Day Up"); } }
class StudentDemo { public Student getStudent() { return new Student(); } }
class StudentTest3 { public static void main(String[] args) { //如何调用的呢? StudentDemo sd = new StudentDemo(); //Student s = sd.getStudent(); //s.study(); //这里就是所谓的链式编程(每次调用完毕方法后,返回的是一 //个对象。) sd.getStudent().study(); } } |
包(package):
A:其实就是文件夹
B:作用
a:把相同的类名放到不同的包中
b:对类进行分类管理
举例:
学生:增加,删除,修改,查询
老师:增加,删除,修改,查询
...
方案1:按照功能分
cn.itcast.add
AddStudent
AddTeacher
cn.itcast.delete
DeleteStudent
DeleteTeacher
cn.itcast.update
UpdateStudent
UpdateTeacher
cn.itcast.find
FindStudent
FindTeacher
方案2:按照模块分
cn.itcast.teacher
AddTeacher
DeleteTeacher
UpdateTeacher
FindTeacher
cn.itcast.student
AddStudent
DeleteStudent
UpdateStudent
FindStudent
包的定义
package 包名;
多级包用.分开即可
注意事项:
A:package语句必须是程序的第一条可执行的代码
B:package语句在一个java文件中只能有一个
C:如果没有package,默认表示无包名
带包的编译和运行:
A:手动式
a:编写一个带包的java文件。
b:通过javac命令编译该java文件。
c:手动创建包名。
d:把b步骤的class文件放到c步骤的最底层包
e:回到和包根目录在同一目录的地方,然后运行
带包运行。
B:自动式
a:编写一个带包的java文件。
b:javac编译的时候带上-d即可
javac -d . HelloWorld.java
c:回到和包根目录在同一目录的地方,然后运行
带包运行。
demo: |
package cn.itcast;
class HelloWorld { public static void main(String[] args) { System.out.println("HelloWorld"); } } |
导包:
格式:import 包名;
这种方式导入是到类的名称。
注意:我们用谁就导谁。
面试题:
package,import,class有没有顺序关系?
有。
package > import > class
Package:只能有一个
import:可以有多个
class:可以有多个,以后建议是一个
权限修饰符的范围:
修饰符:
权限修饰符:private,默认的,protected,public
状态修饰符:static,final
抽象修饰符:abstract
类:
权限修饰符:默认修饰符,public
状态修饰符:final
抽象修饰符:abstract
用的最多的就是:public
成员变量:
权限修饰符:private,默认的,protected,public
状态修饰符:static,final
用的最多的就是:private
构造方法:
权限修饰符:private,默认的,protected,public
用的最多的就是:public
成员方法:
权限修饰符:private,默认的,protected,public
状态修饰符:static,final
抽象修饰符:abstract
用的最多的就是:public
除此以外的组合规则:
成员变量:public static final
成员方法:public static
public abstract
public final
*/
//此处不允许使用修饰符private
//此处不允许使用修饰符protected
//此处不允许使用修饰符static
public class Demo {
//成员变量
private int x = 10;
int y = 20;
protected int z = 30;
public int a = 40;
public final int b = 50;
public static int c = 60;
public static final int d = 70;
//此处不允许使用修饰符abstract
//abstract int e = 80;
//构造方法
private Demo(){}
Demo(String name){}
protected Demo(String name,int age) {}
public Demo(String name,int age,String address) {}
//此处不允许使用修饰符static
//public static Demo(){}
//此处不允许使用修饰符final
//public final Demo() {}
//此处不允许使用修饰符abstract
//public abstract Demo(){}
//成员方法
//static void show() {}
//abstract void show();
//final void show(){}
}
内部类的概述和讲解:
内部类概述:
把类定义在其他类的内部,这个类就被称为内部类。
举例:在类A中定义了一个类B,类B就是内部类。
内部的访问特点:
A:内部类可以直接访问外部类的成员,包括私有。
B:外部类要访问内部类的成员,必须创建对象。
demo: |
class Outer { private int num = 10;
class Inner { public void show() { System.out.println(num); } }
public void method() { //找不到符号 //show();
Inner i = new Inner(); i.show(); }
}
class InnerClassDemo { public static void main(String[] args) {
} } |
内部类位置
成员位置:在成员位置定义的类,被称为成员内部类。
局部位置:在局部位置定义的类,被称为局部内部类。
成员位置:在成员位置定义的类,被称为成员内部类。
Demo: |
class Outer { private int num = 10;
//成员位置 /* class Inner {
} */
public void method() { //局部位置 class Inner {
} } }
class InnerClassDemo2 { public static void main(String[] args) {
} } |
成员内部类:
如何直接访问内部类的成员。
外部类名.内部类名 对象名 = 外部类对象.内部类对象;
Demo: |
class Outer { private int num = 10;
class Inner { public void show() { System.out.println(num); } } }
class InnerClassDemo3 { public static void main(String[] args) { //需求:我要访问Inner类的show()方法 //Inner i = new Inner(); //i.show();
//格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象; Outer.Inner oi = new Outer().new Inner(); oi.show(); } } |
成员内部类的修饰符:
private 为了保证数据的安全性
static 为了方便访问数据
注意:静态内部类访问的外部类数据必须用静态修饰。
案例:我有一个人(人有身体,身体内有心脏。)
class Body {
private class Heart {
public void operator() {
System.out.println("心脏搭桥");
}
}
public void method() {
if(如果你是外科医生) {
Heart h = new Heart();
h.operator();
}
}
}
按照我们刚才的讲解,来使用一下
Body.Heart bh = new Body().new Heart();
bh.operator();
//加了private后,就不能被访问了,那么,怎么玩呢?
Body b = new Body();
b.method();
Demo: |
class Outer { private int num = 10; private static int num2 = 100;
//内部类用静态修饰是因为内部类可以看出是外部类的成员 public static class Inner { public void show() { //System.out.println(num); System.out.println(num2); }
public static void show2() { //System.out.println(num); System.out.println(num2); } } }
class InnerClassDemo4 { public static void main(String[] args) { //使用内部类 // 限定的新静态类 //Outer.Inner oi = new Outer().new Inner(); //oi.show(); //oi.show2();
//成员内部类被静态修饰后的访问方式是: //格式:外部类名.内部类名 对象名 = new 外部类名.内部类名(); Outer.Inner oi = new Outer.Inner(); oi.show(); oi.show2();
//show2()的另一种调用方式 Outer.Inner.show2(); } } |
局部内部类
A:可以直接访问外部类的成员
B:在局部位置,可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能
面试题:
局部内部类访问局部变量的注意事项?
A:局部内部类访问局部变量必须用final修饰
B:为什么呢?
局部变量是随着方法的调用而调用,随着调用完毕而消失。
而堆内存的内容并不会立即消失。所以,我们加final修饰。
加入final修饰后,这个变量就成了常量。既然是常量。你消失了。
我在内存中存储的是数据20,所以,我还是有数据在使用。
Demo: |
class Outer { private int num = 10;
public void method() { //int num2 = 20; //final int num2 = 20; class Inner { public void show() { System.out.println(num); //从内部类中访问本地变量num2; 需要被声明为最终类型 System.out.println(num2);//20 } }
//System.out.println(num2);
Inner i = new Inner(); i.show(); } }
class InnerClassDemo5 { public static void main(String[] args) { Outer o = new Outer(); o.method(); } } |
匿名内部类
就是内部类的简化写法。
前提:存在一个类或者接口
这里的类可以是具体类也可以是抽象类。
格式:
new 类名或者接口名(){
重写方法;
}
本质是什么呢?
是一个继承了该类或者实现了该接口的子类匿名对象。
Demo: |
interface Inter { public abstract void show(); public abstract void show2(); }
class Outer { public void method() { //一个方法的时候 /* new Inter() { public void show() { System.out.println("show"); } }.show(); */
//二个方法的时候 /* new Inter() { public void show() { System.out.println("show"); }
public void show2() { System.out.println("show2"); } }.show();
new Inter() { public void show() { System.out.println("show"); }
public void show2() { System.out.println("show2"); } }.show2(); */
//如果我是很多个方法,就很麻烦了 //那么,我们有没有改进的方案呢? Inter i = new Inter() { //多态 public void show() { System.out.println("show"); }
public void show2() { System.out.println("show2"); } };
i.show(); i.show2(); } }
class InnerClassDemo6 { public static void main(String[] args) { Outer o = new Outer(); o.method(); } } |