继承
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。
继承是is-a 的相互关系
继承的优点
将所有子类的共同属性放入父类,实现代码共享,避免重复,提高开发效率
可以使得修改扩展继承而来的实现比较简单
继承的缺陷
父类变,子类就必须变
继承破坏了封装,对于父类而言,它的实现细节对与子类来说都是透明的
继承是一种强耦合关系
特殊关键字
包package
包是类或接口的容器,是一个用于避免命名冲突的名空间,是一个逻辑命名的概念,与具体的物理位置无关
在具体的实现中,包名称经常和目录名称对应
什么是包
1、包是类的组织方式,提供名空间和访问控制
2、类似于文件系统的组织
声明包中的类package
语法:package 包名称;
声明包要求是源代码文件的第一个语句。包定义之前可以添加注释消息
程序中最多只能有一条package语句,没有包定义的源代码文件成为默认包中的一部分
程序中如果有 package 语句 , 该语句必须是第一条语句(前面只能有注释或空行)
包的命名规则:
全小写
使用域名反转的方式定义,例如餐饮集团canyin.com 的项目,定义包名称为 com.canyin
包的作用
如果其他人想使用包中类,则需要使用全名
import
java
.
util
.
Date
;
public class
A
{
public static
void
main
(
String
[]
args
){
Date now
=
new
Date
();
//
使用类的简称
Date
,而不是全名称
java.util.Date
}
}
为了简化书写, Java 提供了 import 语句: import package_name.* ;
import java . util . * ;
//使用 java.util 包中的所有类都不需要再使用 import java.util. 类名
引入包中的某一个类: import java.util.ArrayList;
引入包import
1、Java 缺省引入的包为 java.lang
System
.
out
.
println
(
"
显示输出
"
);
//
不需要
import java.lang.System
//同包中的其它类不需要导入
package
com
.
yan
;
public class
A
{}
package
com
.
yan
;
public class
B
{
public
void
pp
(){
A a
=
new
A1
();
//
不需要
import com.yan.A
}
}
2、引入包中的类: import 包名称 . 类名称 ; 例如 import java.util.Date;
3、引入整个包; import 包名称 .* ; 例如 import java.util.* ;
4、不引入包而是用类,则需要是用类的全名: 包名 . 类名 , 例如java.util.Date dd=new
包说明
1、package-info.java 可以描述一个包的作用
//这是一个测试包
package
com
.
yan
.
test
;
2、package-info 中不能定义 public 和 private 的类,但是可以定义 friendly 的类及包常量,提供给统一包下面的类进行共享
package
com
.
yan
.
a
;
import
lombok
.
Data
;
class
Constants
{
public static final
String
NAME
=
"Yanjun"
;
}
@Data
class
Teacher
{
//
包中的类可以直接使用
private
String
className
;
}
范围限定词和包
//
定义不包含再其它类中的外部类时,
class
前的范围限定词可以使用
public
或者默认
//public
到处可见 没有限定词只能同包访问
package
com
.
yan
;
public class
A
{
public static
void
main
(
String
args
){
B b
=
new
B
();
//
语法正确
}
}
class
B
{}
package
com
.
yan1
;
public class
C
{
public static
void
main
(
String
[]
args
){
B b
=
new
B1
();
//
语法错误,因为
B
类是默认
class
}
}
//
成员属性和成员方法
:
定义在
class
内部,除了构造器(匿名内部代码块)和析构器之外的其它内容
public class
A
{
public
A
(){}
//
方法名称和类名称一致,包括大小写,而且没有返回类型声明
---
构造器
//构造器方法不能直接调用,只能通过
new
运算符进行间接调用
new A()
系统自动执行
A()
方法
public
int
A
(){}
//
语法正确,但是不是构造器。可以直接调用
,new A().A()
//成员方法
public范围限定词 返回数据类型 方法名称
(
参数类型
1
形参名称
1
,...){
//
如果没有返回值则
类型为
void
return
xxx
;
返回值必须和返回类型声明一致;如果返回类型为
void
则
return
后面不能带任何数据
}
//
成员方法的调用为 对象名
.
方法名称
(
实际参数列表
)
}
抽象
1、忽略掉一个对象或实体的细节而只关注其本质特征的过程,可以简化功能与格式,帮助用户与对象交互是人类解决问题的基本法宝。良好的抽象策略可以控制问题的复杂程度,增强系统的通用性和可扩展性
2、抽象主要包括过程抽象和数据抽象
(1)过程抽象是将问题域中具有明确功能定义的操作抽取出来,并将其作为一个实体看待
(2)数据抽象是较过程抽象更高级别的抽象方式,将描述客体的属性和行为绑定在一起,实现统一的抽象,从而达到对现实世界客体的真正模拟
类
1、类是构造对象的模板和蓝图。通俗地说,类相当于建筑的图纸,而对象相当于建筑物。由类构造对象的过程称为创建对象的实例。Java 中通过关键字 class 定义 “ 类 ” ,后跟类名
2、设计与编写类的过程实际上是一个对实体共有属性和行为的一个抽象的过程
例如面对的是一个具体个体:赵小胖,为了将研究对象存储在计算机中,所以定义了一个新数据类型Student
class Student {}
分析问题域相关的属性:
class
Student
{
private
Long
id
;
如果使用包装类,则默认值为
null
private
String
username
=
”yanjun”
;
private
int
age
;
如果使用简单类型,则数值型默认为
0
,
布尔型为
false
}
分析问题域相关的行为 --- 方法
class
Student
{
public
void
study
(){}
public
void
sleep
(){}
private
Long
id
;
如果使用包装类,则默认值为
null
private
String
username
=
”yanjun”
;
private
int
age
;
}
定义类的目的就是为了在计算机中存储特定的对象,所以需要创建对应的对象,创建方法和简单类型中定义变量的含义一致
Student s1 = new Student ();
s1 . 方法名 (); 调用成员方法
new Stduent (). sleep ();
面向对象的编程可以认为是面向类的编程。编写类的过程,相当于我们定义了一种新的数据类型。
面向对象编程的核心是面向抽象编程,面向抽象编程的核心是面向接口编程
面向对象与面向过程的区别
面向过程:
优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源; 比如单片机、嵌入式开发、Linux/Unix 等一般采用面向过程开发,性能是最重要的因素。
缺点:没有面向对象易维护、易复用、易扩展
面向对象:
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
缺点:性能比面向过程低
例题
1、猜数字游戏
需要记录猜数的整个过程
根据猜测的次数进行评价
package com.yan3;
import java.util.Scanner;
public class GuessName {
private int target;
private int count = 0;
private int[] history = new int[15];
private boolean flag = false;
public void begin() {
Scanner sc = new Scanner(System.in);
while (count < 15) {
System.out.println("第" + (count + 1) + "次猜测的数据为: 输入-1表示退出");
int tmp = sc.nextInt();
if (tmp == -1) {
System.exit(0);
// return;
}
String res = guess(tmp);
if ("success".equals(res)) {
break;
} else {
System.out.println(res);
// System.out.println(count);
}
}
if (count < 5) {
System.out.println("你好厉害,不愧是天才!");
} else if (count < 10) {
System.out.println("还可以,一般般,继续努力!");
} else if (count < 15) {
System.out.println("还行吧,比猪的智商够!");
} else {
System.out.println("你和猪没法比!!!");
}
showHistory();
sc.close();
}
private void showHistory() {
System.out.println("=====================");
if (flag) {
System.out.println("恭喜你,猜对了!");
}
for (int i = 0; i < count; i++) {
System.out.println("第" + (i + 1) + "次猜测的数据为" + history[i]);
}
}
private String guess(int num) {
String res = "";
if (num == target) {
flag = true;
res = "success";
} else if (num < target) {
res = "猜小了!";
} else {
res = "猜大了!";
}
history[count++] = num;
return res;
}
public static void main(String[] args) {
// 猜数字游戏
// 需要记录才输得整个过程
// 根据猜测的次数进行评价
GuessName game = new GuessName();
game.setTarget(1234);
game.begin();
}
// ===================================================
public void setTarget(int target) {
this.target = target;
}
}
2、计算圆的面积和周长,输入半径值
package com.yan3;
import java.util.Scanner;
public class Circle {
// 2、计算圆的面积和周长,输入半径值
private double redis;
public static final double PI = Math.PI;
public double getArea() {
return Constans.PI * redis * redis;
}
public double get() {
return 2 * Constans.PI * redis;
}
public static void main(String[] args) {
System.out.println("半径?退出-1");
Scanner sc = new Scanner(System.in);
Circle t = new Circle();
while (true) {
double r = sc.nextDouble();
System.out.println(r);
if (r < 0) {
break;
} else {
t.setRedis(r);
System.out.println("圆的面积:" + t.getArea() + "圆的周长:" + t.get());
}
}
sc.close();
}
public void setRedis(double redis) {
this.redis = redis;
}
}
3、请定义一个交通工具 Vehicle 的类,其中有 :
属性:速度(speed) ,车的类型 (type) ;方法:移动 (move()) ,设置速度 (setSpeed(double s)) ,加速speedUp(double s),减速 speedDown(double s) 。最后在测试类 Vehicle 中的 main() 中实例化一个交通工具对象,
并通过构造方法给它初始化speed,type 的值,并且打印出来。另外,调用加速,减速的方法对速度进行改变。
package com.yan3;
public class Vehicle {
// 3、请定义一个交通工具Vehicle的类,其中有:
// 属性:速度(speed),车的类型(type);方法:移动(move()),设置速度(setSpeed(double s)),
// 加速speedUp(double s),减速speedDown(double s)。最后在测试类Vehicle中的main()中
// 实例化一个交通工具对象,并通过构造方法给它初始化speed,type的值,并且打印出来。另外,调用加速,减速的方法对速度进行改变。
private double speed;
private String type;
public void speedUp(double s) {
speed += s;
}
void speedDown(double s) {
speed -= s;
}
public void move() {
System.out.println("以" + speed + "开始移动");
}
public static void main(String[] args) {
Vehicle vv = new Vehicle();
vv.setSpeed(12);
vv.move();
vv.setType("大众");
vv.speedUp(2);
vv.move();
vv.speedDown(12);
vv.move();
}
//=============================================
public double getSpeed() {
return speed;
}
public void setSpeed(double s) {
this.speed = s;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
4、利用继承来描述人,老师,学生之间的关系
1 )老师含有属性: name , age , subject ,含有方法: eat , teach , toString
2 )学生含有属性: name , age , class ,含有方法: eat , study , toString
3 )利用继承的思想,从老师和学生中抽象出人,并创建 Test 进行调用并输出( System.out )
package com.yan4;
public class Test1 {
public static void main(String[] args) {
Teacher t = new Teacher();
t.setName("yanjun");
t.setAge(18);
t.setSubject("数学");
System.out.println(t);
Student s = new Student();
s.setName("bai");
s.setAge(15);
s.setClz("20220604");
System.out.println(s);
}
}
class Person {
private String name;
private int age;
public void eat() {
System.out.println("正在吃饭……");
}
public String toString() {
return "姓名为" + name + ",现在年龄为" + 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 Teacher extends Person {
private String subject;
public void teach() {
System.out.println("正在上课……");
}
public String toString() {
return "教师姓名为" + getName() + ",现在年龄为" + getAge() + ",教授的课程为" + subject;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
}
class Student extends Person {
private String clz;
public void study() {
System.out.println("正在学习……");
}
public String toString() {
return "学生姓名为" + getName() + ",现在的年龄为" + getAge() + ",所在的班级" + clz;
}
public String getClz() {
return clz;
}
public void setClz(String clz) {
this.clz = clz;
}
}
5、定义一个类Calculate1,实现加、减两种运算,然后编写一个派生类Calculate2,实现乘除两种算法
package com.yan4;
public class Test2 {
public static void main(String[] args) {
Calculate1 cc1 = new Calculate1();
cc1.setA(2);
cc1.setB(3);
System.out.println(cc1.add());
System.out.println(cc1.subtract());
Calculate2 cc2 = new Calculate2();
cc2.setA(2);
cc2.setB(3);
System.out.println(cc2.add());
System.out.println(cc2.subtract());
System.out.println(cc2.mutiply());
System.out.println(cc2.divide());
}
}
class Calculate2 extends Calculate1 {
public int mutiply() {
return getA() * getB();
}
public double divide() {
if (getB() != 0) {
return 1. * getA() / getB();
}
return 0;
}
}
class Calculate1 {
private int a, b;
public int add() {
return a + b;
}
public int subtract() {
return a - b;
}
// ==============================
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
}