什么是包?
包是用来分门别类的管理各种不同类的,类似于文件夹、建包利于程序的管理和维护。
建包的语法格式:
package 公司域名倒写.技术名称
。报名建议全部英文小写,且具备意义建包语句必须在第一行,一般IDEA工具会帮助创建
package com.itheima.javabean;
public class Student {
}
导包
相同包下的类可以直接访问,不同包下的类必须导包,才可以使用!导包格式:
import 包名.类名
;假如一个类中需要用到不同类,而这个两个类的名称是一样的,那么默认只能导入一个类,另一个类要带包名访问。
什么是权限修饰符?
权限修饰符:是用来控制一个成员能够被访问的范围的。
可以修饰成员变量,方法,构造器,内部类,不同权限修饰符修饰的成员能够被访问的范围将受到限制。
权限修饰符的分类和具体作用范围:
权限修饰符:有四种作用范围由小到大
(private -> 缺省 -> protected - > public )
修饰符 | 同一个类中 | 同一个包中其他类 | 不同包下的子类 | 不同包下的无关类 |
---|---|---|---|---|
private | √ | |||
缺省(不写) | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
权限修饰符的作用
能够识别别人定义的成员的访问权限。
自己定义成员(方法,成员变量,构造器等)一般满足如下要求:
成员变量一般私有。
方法一般公开。
如果该成员只希望本类访问,使用private修饰。
如果该成员只希望本类,同一个包下的其他类和子类访问,使用protected修饰。
final的作用
final 关键字是最终的意思,可以修饰(方法,变量,类)
修饰方法:表明该方法是最终方法,不能被重写。
修饰变量:表示该变量第一次赋值后,不能再次被赋值(有且仅能被赋值一次)。
修饰类:表明该类是最终类,不能被继承。
class Person {
// final修饰方法为最终方法, 不能被重写
public final void run() {
System.out.println("人可以奔跑");
}
}
class Student extends Person {
// final修饰不能重写
public void run() {
System.out.println("学生可以奔跑");
}
}
public static void main(String[] args) {
// final修饰变量后, 只能被赋值一次
final int num;
num = 20;
// 只能赋值一次
num = 30;
}
// final修饰类为最终类, 不能被继承
final class Person{
}
// 继承会报错
class Student extends Person {
}
final修饰变量的注意
final修饰的变量是基本类型:那么变量存储的
数据值
不能发生改变。final修饰的变量是引用类型:那么变量存储的
地址值
不能发生改变,但是地址指向的对象内容是可以发生变化的。
认识常量
常量是使用了
public static final
修饰的成员变量,必须有初始化值,而且执行的过程中其值不能被改变。常量的作用和好处:可以用于做系统的配置信息,方便程序的维护,同时也能提高可读性。
常量命名规范:英文单词全部大写,多个单词下划线连接起来。
public class Constant {
// 常量命名英文单词全部使用大写
public static final String FIRST_NAME = “chen";
public static final String LAST_NAME = “yq";
public static final String PASS_WORD = “123456";
}
常量的执行原理:
在编译阶段会进行“宏替换”,把使用常量的地方全部替换成真实的字面量。
这样做的好处是让使用常量的程序的执行性能与直接使用字面量是一样的。
选择常量做信息标志和分类:
代码可读性好,实现了软编码形式。
枚举的概述
枚举是Java中的一种特殊类型, 枚举虽然不是class声明, 但也是类
枚举的作用:“是为了做信息的标志和信息的分类”。
定义枚举类的格式:
修饰符 enum 枚举名称{
第一行都是罗列枚举类实例的名称。
}
// 定义枚举类
public enum Season {
// 第一行必须罗列枚举的对象名称, 建议全部大写
SPRING , SUMMER , AUTUMN , WINTER;
}
反编译后观察枚举的特征:
Compiled from "Season.java"
public final class Season extends java.lang.Enum<Season> {
public static final Season SPRING = new Season();
public static final Season SUMMER = new Season();
public static final Season AUTUMN = new Season();
public static final Season WINTER = new Season();
public static Season[] values();
public static Season valueOf(java.lang.String);
}
枚举的特征:
枚举类都是继承了枚举类型:java.lang.Enum
枚举都是最终类,不可以被继承。
构造器都是私有的,枚举对外不能创建对象。
枚举类的第一行默认都是罗列枚举对象的名称的。
枚举类相当于是多例模式。
选择常量做信息标志和分类:
虽然可以实现可读性,但是入参值不受约束,代码相对不够严谨。
枚举做信息标志和分类:
代码可读性好,入参约束严谨,代码优雅,是最好的信息分类技术!建议使用!
认识抽象类
某个父类知道其所有子类要完成的功能, 但是每个子类完成情况都不一样, 父类就只定义该功能的基本要求, 具体实现由子类完成, 这个类就可以是一个抽象类, 如果说我们之前定义的类时完整的设计图, 那么抽象类其实就是一种
不完全的设计图
,抽象类必须用abstract修饰
。
抽象类语法格式
修饰符 abstract class 类名{}
认识抽象方法
抽象方法就是在抽象类中定义的子类必须完成的功能的基本要求
如果一个类中的某个方法的具体实现不能确定,就可以申明成abstract修饰的
抽象方法
, 抽象方法没有方法体, 只有方法前面, 同样必须使用abstract修饰
抽象方法语法格式
修饰符 abstract 返回值类型 方法名称(形参列表);
示例代码
// 定义抽象类
public abstract class Person {
// 定义抽象方法, 抽象方法没有方法体
public abstract void study();
}
class Student extends Person{
@Override
// 子类就必须实现抽象类定义的抽象方法, 没有实现就会报错
public void study() {
}
}
抽象的使用总结与注意事项
抽象类可以理解成类的不完整设计图,是用来被子类继承的。
一个类如果继承了抽象类,那么这个类
必须重写完抽象类的全部抽象方法
,否则这个类也必须定义成抽象类。
系统需求
某加油站推出了2种支付卡,一种是预存10000的金卡,后续加油享受8折优惠,另一种是预存5000的银卡 ,后续加油享受8.5折优惠。
请分别实现2种卡片进入收银系统后的逻辑,卡片需要包含主人名称,余额,支付功能。
分析实现
创建一张卡片父类:定义属性包括主人名称、余额、支付功能(具体实现交给子类)
创建一张白金卡类:重写支付功能,按照原价的8折计算输出。
创建一张银卡类:重写支付功能,按照原价的8.5折计算输出。
// 定义抽象父类
public abstract class Card {
private String name;
private double money;
// 定义抽象方法
public abstract void pay(double money);
// getter和setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
}
// 定义金卡子类
class GoldCard extends Card {
@Override
// 将父类的抽象方法实出来
public void pay(double money) {
System.out.print("您当前金额是:" + getMoney());
setMoney(getMoney() - money * 0.8);
System.out.println(" 优惠后您需要支付的金额是:" + money * 0.8 + " 您的账户余额为:" + getMoney() );
}
}
测试代码
public class Test {
public static void main(String[] args) {
// 测试代码
GoldCard card1 = new GoldCard();
card1.setName("chenyq");
card1.setMoney(10000.0);
card1.pay(1000.0);
// 测试结果
// 您当前金额是:10000.0 优惠后您需要支付的金额是:800.0 您的账户余额为:9200.0
}
}
抽象类特征和注意事项
有得有失: 得到了抽象方法,
失去了创建对象的能力
。抽象类为什么不能创建对象?
- 因为抽象类就是一个模板, 如果抽象类创建了对象, 创建出来的对象又不能使用抽象方法, 所以Java禁止抽象类创建对象
类有的成员(成员变量、方法、构造器)抽象类都具备
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
一个类继承了抽象类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
不能用abstract修饰变量、代码块、构造器。
补充: final和abstract是什么关系?
互斥关系
abstract定义的抽象类作为模板让子类继承,final定义的类不能被继承。
抽象方法定义通用功能让子类重写,final定义的方法子类不能重写。
模板方法我们是建议使用final修饰的,这样会更专业,那么为什么呢?
模板方法是给子类直接使用的,不是让子类重写的,一旦子类重写了模板方法就失效了。
什么是接口?
接口就是体现规范的额, 其中是用抽象方法定义的一组行为规范, 接口是更加彻底的抽象
接口的定义与特点
接口用
关键字interface
来定义, 接口的格式如下:我们先来学习JDK8之前的接口, JDK8之前接口中只能是抽象方法和常量,没有其他成分了。
接口不能实例化, 接口中的成员都是public修饰的,写不写都是,因为规范的目的是为了公开化。
public interface 接口名 {
// 常量
// 抽象方法
}
演示代码
/**
创建接口
*/
public interface Test {
// JDK8之前接口中只有常量和抽象方法
// 1.常量
public static final String FIRST_NAME = "Chen";
// 修饰常量的public static final在接口中可以省略, 会默认添加
String LAST_NAME = "yq";
// 2.抽象方法
public abstract void run();
// 修饰抽象方法的public abstract在接口中可以省略, 会默认添加
void eat();
}
接口的用法:
接口是用来被类实现的,实现
关键字是implements
, 实现接口的类称为实现类
。实现类可以理解成接口所谓的子类。
语法规范如下
修饰符 class 实现类名 implements 接口1, 接口2, 接口3 , ... {
}
从上面可以看出,接口可以被类单实现,也可以被类多实现。
演示代码:
public interface SportMan {
// 表示运动员要跑步
void run();
}
public interface Law {
// 表示遵守法律
void rule();
}
public class PingPongMan implements SportMan{
@Override
// 对SportMan接口的抽象方法进行实现
public void run() {
System.out.println("运动员要跑步");
}
}
public class PingPongMan implements SportMan, Law{
@Override
// 1.对SportMan接口的抽象方法进行实现
public void run() {
System.out.println("运动员要跑步");
}
// 2.对Lwa接口的抽象方法进行实现
@Override
public void rule() {
System.out.println("运动员要遵纪守法");
}
}
接口实现的注意事项:
一个类实现接口,必须重写完全部接口的全部抽象方法,否则这个类需要定义成抽象类。
接口多继承的作用
规范合并,整合多个接口为同一个接口,便于子类实现。
例如我们有如下三个接口, 当我们想要对三个接口多实现时, 需要一一的将三个接口都写出来, 如果有更多接口, 我们书写就会变困难
public interface People {
void eat();
}
public interface Law {
// 表示遵守法律
void rule();
}
public interface SportMan {
// 表示运动员要跑步
void run();
}
我们可以让其中一个接口继承另外两个接口, 先进行多继承再实现多继承后的接口
// 接口的多继承
public interface People extends Law, SportMan {
void eat();
}
此时想要对三个接口进行实现, 只需要实现People接口即可
public class PingPongMan implements People{
@Override
public void rule() {
System.out.println("运动员遵纪守法");
}
@Override
public void eat() {
System.out.println("运动员吃饭");
}
@Override
public void run() {
System.out.println("运动员跑步");
}
}
简单小结
类和类的关系:单继承。
类和接口的关系:多实现。
接口和接口的关系:多继承,一个接口可以同时继承多个接口。
- 规范合并可以多继承
- 规范冲突是不能进行多继承的
JDK8版本开始后,Java只对接口的成员方法进行了新增
允许接口中直接定义
带有方法体的方法
第一种:默认方法
类似之前写的普通实例方法:必须用default修饰
默认会public修饰。需要用
接口的实现类的对象来调用
public interface People {
// 定义默认方法, 也就是实例方法, 必须default修饰
default void run() {
System.out.println("正在跑步");
}
}
class Student implements People {
}
class Test {
public static void main(String[] args) {
Student stu = new Student();
// 接口的实例方法, 由实现接口类的实例对象调用
stu.run();
}
}
第二种:静态方法
默认会public修饰,必须static修饰。
注意:接口的静态方法必须用
本身的接口名来调用
, 实现类不能调用。
public interface People {
// 定义静态方法, 必须static修饰
static void eat() {
System.out.println("正在吃饭");
}
}
class Test {
public static void main(String[] args) {
// 接口中的静态方法, 由本身的接口名调用
People.eat();
}
}
第三种:私有方法
就是私有的实例方法:,必须使用private修饰,从JDK 1.9才开始有的。
只能在本接口中被其他的
默认方法或者私有方法
访问。
public interface People {
// 定义JDK9接口的私有方法, 必须使用private修饰
private void study() {
}
}
注意:JDK8新增的3种方法我们自己在开发中很少使用,通常是Java源码涉及到的,我们需要理解、识别语法、明白调用关系即可
接口的注意事项
1、接口不能创建对象
2、一个类实现多个接口,多个接口中有同样的静态方法不冲突。
3、一个类继承了父类,同时又实现了接口,父类中和接口中有同名方法,默认用父类的。
4、一个类实现了多个接口,多个接口中存在同名的默认方法,不冲突,这个类重写该方法即可。
5、一个接口继承多个接口,是没有问题的,如果多个接口中存在规范冲突则不能多继承。