分包思想
如果将所有的类文件都放在同一个包下,不利于管理和后期维护。所以,对于不同功能的类文件,可以放在不同的包下进行管理
- 包的概述和定义
问题:
1.创建包时,包的命名规则有怎样的要求?
2.Java中是用哪一个关键字表示包?
3.使用idea时,是否需要手动给一个类定义包?
包本质上是文件夹,里面放类文件。如果所有的类文件放在一个包下,不方便管理
包的定义
使用package定义包(import关键字是导入包)
多级包用“.”隔开,都是小写字母
多级包名,是企业网址翻转,例如:com.itheima.*就是我们写的包名
不用手动给类定义包,使用idea生成
思考:为什么包名推荐用公司域名,并且还是反写的形式?
公司域名具有唯一性,并且你所开发的是企业级应用程序,只属于企业
当你域名反写的时候,你的代码会直接放在相关文件夹下,如果不反写,所有的代码都在com下 - 包的注意事项和类访问
问题:
1.在类中,使用package定义包时,需要注意哪些问题?
2.在一个类中访问另一个类,什么时候不需要导包?
3.全类名由哪些部分组成,一般出现的场景是什么?
包的注意事项:
package语句必须是程序的第一条可执行语句
package语句在一个java文件中只能有一个
如果没有package,默认表示无包名
类与类之间的访问
同一个包下:不需要导包
不同的包下:
import导包
通过全类名(包名+类名)访问:代码中同一个类下,要访问两个包下名字相同的类时
import、package、class三个关键字的摆放位置存在顺序关系
package必须是程序的第一条可执行的代码
import需要写在package下面
class需要在import下面
权限修饰符
问题:
1.在java中,权限修饰级别有几种,分别对应哪些关键字?
2.对于没有用任何权限修饰符修饰的方法,能否在不同的包下被访问?
3.对于使用protected修饰的方法,该类的子类是否在任何包下都可以访问这个方法?
test1包
/**
- 1.在test1包下创建一个Fu类,定义默认和保护两种级别的方法
- 2.分别在不同包下写一个子类继承Fu类,去调用父类的两个方法
- 3.分别在不同包下写测试类验证
*/
public class Fu {
void show() {
System.out.println(“默认权限 ---- show方法”);
}
protected void print() {
System.out.println(“protected权限 ---- print方法”);
}
}
public class Zi extends Fu {
// 同一个包下, 被子类访问
public void method() {
super.show();
}
}
public class Test {
public static void main(String[] args) {
// 同一个包下, 无关类访问
Fu f = new Fu();
f.show();
}
}
test2包
import com.itheima.test1.Fu;
public class Son extends Fu {
// 不同包下, 被子类访问
public void method(){
// super.show();
super.print();
}
}
public class Test {
public static void main(String[] args) {
// 不同包下, 被无关类访问
Fu f = new Fu();
//f.show();
//f.print();
}
}
final
问题:
-
final关键字有什么作用?
-
final关键字可以修饰哪些内容?
-
被final修饰的变量如果是引用数据类型,有什么特点?
fianl关键字的作用:
final关键字代表最终的意思,可以修饰成员方法,变量,类
final修饰的特点:
fianl修饰类:该类不能被继承(不能有子类,但是可以有父类)
final修饰方法:该方法不能被重写
final修饰变量:该变量不能再次赋值
变量是基本类型,不能改变的是值
变量是引用类型,不能改变的是地址值,但地址里面的内容是可以改变的
举例:
public static void main(String[] args){
final Student s = new Student(23);
//s = new Student(24); // 编译错误
s.setAge(24); // 正确
}
命名规范:如果是一个单词,所有字母大写,如果是多个单词,所有字母大写之外,还需要单词间用下划线分隔,例如:final int MAX_VALUE = 20;
练习:以下代码哪些是有问题的,为什么?
public class Student {
final int age;public void setAge(int age) {
this.age = age;
}
}
/有问题,因为普通方法是在对象出现之后,才有可能被调用,不调用,这个值不能赋值。被final修饰的变量必须赋值。/
public class Student {
final int age=18;public void setAge(int age) {
this.age = age;
}
}
//有问题,被final修饰的变量不能再次赋值
public class Student {
final static int age;public static void setAge(int a) {
age = a;
}
}
/*
静态方法在类加载的时候就会加载信息,但是不是说方法里面的内容会执行。
方法不调用不能执行。不执行的话,这个变量没有值。被final修饰的变量必须赋值。
*/
public class Student {
final int age;public Student() {
age = 18;
}
}
//正确
常量
概念:在程序运行期间,其值不能发生改变的量
作用:用于做系统的配置信息,方便程序的维护,同时也能提高可读性
命名规范:如果是一个单词,所有字母大写,如果是多个单词,所有字母大写之外,还需要单词间用下划线分隔,例如:final double PI= 3.14;
宏替换:
当定义final变量时就为该变量指定了初始值,并且这个初始值在编译时就可以确定,那么这个变量就是“宏变量”
编译期会把程序中所有用到这个变量的位置直接替换成该变量的值
枚举
为了间接的表示一些固定的值,Java就给我们提供了枚举
是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内 -
定义格式
格式
public enum s {
枚举项1,枚举项2,枚举项3;
}
注意: 定义枚举类要用关键字enum
示例代码
// 定义一个枚举类,用来表示春,夏,秋,冬这四个固定值
public enum Season {
SPRING,SUMMER,AUTUMN,WINTER;
} -
特点
所有枚举类都是Enum的子类
我们可以通过"枚举类名.枚举项名称"去访问指定的枚举项
每一个枚举项其实就是该枚举的一个对象
枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略
枚举类可以有构造器,但必须是private的,它默认的也是private的 -
作用
使用场景:用作信息标志和分类
优势:
常量虽然可以实现可读性,但是入参值不受约束,代码相对不够严谨
枚举代码可读性好,入参约束严谨,建议使用!
案例:
public class Demo {
public static void main(String[] args) {
/**
* 需求:调用发短信的方法,传入对应的节日,即可打印节日短信祝福语
* 方法参数使用字符串类型声明,有什么不足?怎么改进?
*/}
public static void sendMessage(String holiday) {
switch (holiday) {
case “国庆节”:
System.out.println(“莉莉,国庆节快乐!”);
break;
case “劳动节”:
System.out.println(“菲菲,劳动节快乐!”);
break;
case “儿童节”:
System.out.println(“娜娜,儿童节快乐!”);
break;
case “春节”:
System.out.println(“缇娜,国庆节快乐!”);
break;
}
}
}
抽象类 -
抽象类入门
问题:
1.抽象方法具有什么特点?
2.在什么条件下,一个类必须声明为抽象类?
概述:
抽象方法:将共性的行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体明确,该方法就可以定义为抽象方法
抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类
抽象方法的定义格式:
//方法需要用abstract关键字修饰,方法没有方法体
public abstract 返回值类型 方法名(参数列表);
抽象类的定义格式:
//使用abstract关键字修饰类
public abstract class 类名{}
代码案例:
需求:定义猫类(Cat)和狗类(Dog)
猫类成员方法:eat(猫吃鱼)drink(喝水…)
狗类成员方法:eat(狗吃肉)drink(喝水…)
实现步骤:
猫类和狗类中存在共性内容,应向上抽取出一个动物类(Animal)
父类Animal中,无法将 eat 方法具体实现描述清楚,所以定义为抽象方法
抽象方法需要存活在抽象类中,将Animal定义为抽象类
让 Cat 和 Dog 分别继承 Animal,重写eat方法
测试类中创建 Cat 和 Dog 对象,调用方法测试
代码实现:
public abstract class Animal {
public abstract void eat();public void drink() {
System.out.println(“喝水”);
}
}
public class Dog extends Animal{
@Override
public void eat() {
System.out.println(“狗吃屎”);
}
}
public class Cat extends Animal{
@Override
public void eat() {
System.out.println(“猫吃鱼”);
}
}
public class TestAnimal {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat();
dog.drink();
System.out.println(“-------------”);
Cat cat = new Cat();
cat.eat();
cat.drink();
}
}
/**
- 根据初高中的数学知识,不同图形的样式和计算周长的方式都不一样,例如正方形和圆形
- 定义一个抽象类Shape
-
行为:
-
计算周长 celPerimeter
-
返回形状 getType
- 定义一个正方形类Square
-
属性:
-
边长 side
-
行为:
-
设置边长 setSide
-
计算周长 celPerimeter
-
返回形状 getType
- 定义一个三角形类Circle
-
属性:
-
半径 radius
-
行为:
-
设置半径 setRadius
-
计算周长 celPerimeter
-
返回形状 getType
- 根据高中所学几何图形基本知识,完善正方形和圆形类的功能,并在测试类中测试
*/
public abstract class Shape {
public abstract double celPerimeter();
public abstract String getType();
}
public class Square extends Shape {
int side;
public void setSide(int side) {
this.side = side;
}
@Override
public double celPerimeter() {
return side * 4;
}
@Override
public String getType() {
return "正方形";
}
}
public class Circle extends Shape {
int radius;
public void setRadius(int radius) {
this.radius = radius;
}
@Override
public double celPerimeter() {
//Math.PI是得到圆周率,是一个小数,所以最后的结果要强转成int类型
return (2 * Math.PI * radius);
}
@Override
public String getType() {
return "圆形";
}
}
public class TestShape {
public static void main(String[] args) {
Square square = new Square();
square.setSide(3);
double perimeter1 = square.celPerimeter();
System.out.println(square.getType() + “的周长是:” + perimeter1);
Circle circle = new Circle();
circle.setRadius(2);
System.out.println(circle.getType() + "的周长是:" + circle.celPerimeter());
}
}
2. 抽象类的注意事项
问题:
1.在程序中能否使用new关键字调用抽象类的构造方法?
2.在一个抽象类当中,能不能不定义抽象方法?
3.抽象类是否可以定义构造方法?
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
现在没有,不代表以后没有,未雨绸缪
抽象类不能实例化
如果可以实例化,调用抽象方法,没法执行功能。抽象方法没有方法体
可以有构造方法
因为子类的构造方法中有super();
抽象类的子类如果继承抽象类,抽象类有抽象方法的话
要么重写抽象类中的所有抽象方法
要么是抽象类(不推荐)
提问:
abstract能不能和static同时修饰方法?为什么?
抽象方法要求要重写,但是静态方法不能被重写
abstract能不能和final同时修饰方法?为什么?
抽象方法要求要重写,但是final方法不能被重写
3. 模板设计模式
生活中的模板:
短信模板:
情书模板:
问题:
1.设计模式的引入,对于代码编写有什么好处?
2.模板设计模式的优势是什么?
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。
模板设计模式:把抽象类整体就可以看做成一个模板,模板中不能决定的东西定义成抽象方法
让使用模板的类(继承抽象类的类)去重写抽象方法实现需求
模板设计模式的优势:
模板已经定义了通用结构,使用者只需要关心自己需要实现的功能即可
代码案例:
作文模板类:
/*
作文模板类
*/
public abstract class CompositionTemplate {
public final void write(){
System.out.println("<<我的爸爸>>");
//1.是希望调用子类的特有方法,但是子类如何记得写这个特有方法呢?
//2.就给抽象类定义一个抽象方法,这样子类就必须重写
body();
System.out.println("啊~ 这就是我的爸爸");
}
public abstract void body();
}
实现类:
//3.子类继承父类
public class Tom extends CompositionTemplate {
//4.必须重写抽象方法,实现自己特异性的功能
@Override
public void body() {
System.out.println("那是一个秋天, 风儿那么缠绵,记忆中, " +
“那天爸爸骑车接我放学回家,我的脚卡在了自行车链当中, 爸爸蹬不动,他就站起来蹬…”);
}
}
测试类:
public class Test {
public static void main(String[] args) {
Tom t = new Tom();
//5. write方法是从父类继承过来直接使用的
//6. 在write方法内部,调用的body方法是属于子类自己的
t.write();
}
}
接口
- 介绍
生活中的接口:
Java中继承也可以给子类制定规则,但是:
问题:
1.在什么情况下,就可以使用接口优化代码?
2.接口存在的意义是什么?
介绍:
当一个类中的所有方法都是抽象方法的时候,就可以将其定义为接口
接口也是一种引用数据类型,它比抽象类还要抽象
Java中接口存在的两个意义
用来定义规范
用来做功能的拓展
- 定义和特点
问题:
1.在java中,使用什么关键字代表接口?
2.接口是引用数据类型,那是否能够对接口进行实例化?
3.一个类是否可以和多个接口产生联系?
接口用关键字interface修饰
public interface 接口名 {}
类实现接口用implements表示
public class 类名 implements 接口名 {}
接口不能实例化
我们可以创建接口的实现类对象使用
接口的实现类
要么重写接口中的所有抽象方法
要么实现类也是抽象类
一个类可以实现多个接口
//练习一:掌握接口的定义和特点
//1.使用接口的格式创建两个接口,分别是Inter1和Inter2
//2.分在两个接口中各自定义一个方法,分别是study()和print()方法
//3.在测试类TestInterface中,创建接口Inter1的对象,看代码是否有问题
//4.创建一个类InterImpl,实现Inter1接口
//5.在测试类TestInterface中,测试实现类的方法使用
//6.让InterImpl继续实现Inter2接口,查看代码是否有问题
//7.在测试类中测试InterImpl的方法使用
//8.如果既想让InterImpl实现接口Inter2,又不想重写Inter2的抽象方法,该如何处理?
/**
- 练习二:
- 利用接口做参数,写个计算器,能完成加减乘除运算。
- (1)定义一个接口Compute含有一个方法int computer(int n, int m)
- (2)设计四个类分别实现此接口,完成加减乘除运算
*/
public interface Compute {
public abstract int computer(int n, int m);
}
public class Test02 {
public static void main(String[] args) {
Jia jia = new Jia();
System.out.println(jia.computer(2, 3));
Jian jian = new Jian();
System.out.println(jian.computer(3, 2));
Cheng cheng = new Cheng();
System.out.println(cheng.computer(2, 3));
Chu chu = new Chu();
System.out.println(chu.computer(6, 3));
}
}
//加
class Jia implements Compute {
@Override
public int computer(int n, int m) {
return n + m;
}
}
//减
class Jian implements Compute {
@Override
public int computer(int n, int m) {
return n - m;
}
}
//除
class Chu implements Compute {
@Override
public int computer(int n, int m) {
return n / m;
}
}
//乘
class Cheng implements Compute {
@Override
public int computer(int n, int m) {
return n * m;
}
}
3. 接口中的成员特点
问题:
1.在接口中定义的成员变量,实现类是否可以给这个变量重新赋值?
2.是否能够在接口中定义这个接口的构造方法?
3.在JDK8以下版本,接口中的方法都默认是什么方法?
成员特点
成员变量
只能是常量
默认修饰符:public static final
构造方法
没有,因为接口主要是扩展功能的,而没有具体存在
成员方法
只能是抽象方法
默认修饰符:public abstract
关于接口中的方法,JDK8和JDK9中有一些新特性,后面再讲解
/**
- 1.定义一个接口ShapeInter,用来制定相关图形计算的规范
-
属性:
-
圆周率PI:3.1415927
-
行为:
-
计算周长 double celPerimeter();
-
计算面积 double celArea();
-
获取类型 String getType();
- 2.定义圆形类,实现接口,并重写相应方法
- 3.定义正方形类,实现接口,并重写相应方法
- 4.在测试类中验证实现类的方法效果
- 5.接口中的圆周率可以在实现类中更改其值为3.14吗?
*/
public interface ShapeInter {
//圆周率是直接要提供给别人用,而且任何人用都是这个值,这个值也不会改变
double PI = 3.1415927;
//计算周长 double celPerimeter();
public abstract double celPerimeter();
public abstract double celArea();
public abstract String getType();
}
class Circular implements ShapeInter {
double radius;
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public double celPerimeter() {
return 2 * PI * radius;
}
@Override
public double celArea() {
return PI * radius * radius;
}
@Override
public String getType() {
return "圆形";
}
}
public class TestShapeInter {
public static void main(String[] args) {
Circular circular = new Circular();
circular.setRadius(3);
System.out.println(circular.getType()+“的周长是:”+circular.celPerimeter());
System.out.println(circular.getType()+“的面积是:”+circular.celArea());
}
}
4. JDK8版本中成员的特点:默认方法
问题:
1.为什么JDK8要针对接口引入默认方法?
2.如果实现类要重写默认方法,需要注意什么?
3.如果实现类实现的两个接口中,有相同的默认方法,实现类该如何处理?
格式:public default 返回值类型 方法名(参数列表) { }
作用:解决接口升级的问题
范例:
public default void show3() {
}
注意事项:
默认方法不是抽象方法,所以不强制被重写。但是可以被重写,重写的时候去掉default关键字
接口中,public可以省略,default不能省略
如果实现了多个接口,多个接口中存在相同的默认方法声明,子类就必须对该方法进行重写
案例:支付宝和美团
支付宝:
美团:
支付宝和美团都有卡包功能,支付宝的卡包有优惠券和车票,美团的卡包只有优惠券
定义一个接口Function,在里面定义抽象方法card(),代表卡包功能
在接口Function定义一个默认方法scan(),实现扫码功能,实现类对象可直接使用
美团有骑车功能,请在接口Function中定义合适的方法
定义一个美团类Meituan实现该接口,重写相应方法
在测试类中创建美团类对象,分别调用扫码和骑车功能
public class FunctionTest {
public static void main(String[] args) {
Meituan meituan = new Meituan();
meituan.rideBike();
Alipay alipay = new Alipay();
alipay.card();
}
}
//1.定义接口,去规范支付宝和美团的功能
interface Function{
//支付宝和美团的卡包功能,实现是不一样的,所以是抽象方法
public abstract void card();
//支付宝和美团的扫码是一样的,这种情况下,可以定义默认方法,直接给实现类使用
public default void scan() {
System.out.println(“扫码,一分钱也没有,你个穷*”);
}
//美团中有骑车功能,这个骑车功能应该定义成默认方法,因为支付宝当中没有,如果定义成抽象
//会导致支付宝也拥有骑车
public default void rideBike() {
System.out.println(“扫码骑车”);
}
}
//2.定义美团实现类,去实现这个接口
class Meituan implements Function{
@Override
public void card() {
System.out.println(“我只有优惠券”);
}
}
class Alipay implements Function {
@Override
public void card() {
System.out.println(“支付宝的卡包有优惠券还有会员卡还有电影票”);
}
}
5. JDK8版本中接口成员的特点:静态方法
问题:
1.接口中的静态方法能不能被其实现类对象调用?
2.接口的静态方法中,static关键字能否被省略?
3.接口中静态方法的主要作用是什么?
格式:public static 返回值类型 方法名(参数列表) { }
范例:
public static void show() {
}
注意事项:
静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
静态是属于类的,无法被重写
public可以省略,static不能省略
//练习:掌握接口中静态方法的定义和注意事项
public interface Inter {
public static void staticMethod1() {
System.out.println(“接口中的静态public方法”);
}
static void staticMethod2() {
System.out.println(“接口中的静态方法public可以省略不写”);
}
/*
void staticMehtod3(){
System.out.println(“接口中的静态方法,static不能省略”);
}
*/
}
//接口实现类
class InterImpl implements Inter{
//接口中静态方法无法被重写
//@Override
public static void staticMethod1() {
System.out.println(“实现类尝试重写接口的静态方法”);
}
}
public class TestInter {
public static void main(String[] args) {
InterImpl interImpl = new InterImpl();
//调用的是自己的静态方法,不是接口的
interImpl.staticMethod1();
//接口的静态方法,无法被其实现类对象调用
//interImpl.staticMethod2();
//接口的静态方法,只能被“接口名.方法名”调用
Inter.staticMethod1();
Inter.staticMethod2();
}
}
6. JDK9版本中接口成员的特点:私有方法
问题:
1.接口中为什么要引入私有方法,它的作用是什么?
2.在接口中是否能够同时使用private和default修饰方法?
私有方法产生原因
Java 9中新增了带方法体的私有方法,这其实在Java 8中就埋下了伏笔
Java 8允许在接口中定义带方法体的默认方法和静态方法
当两个默认方法或者静态方法中包含一段相同的代码实现时,程序必然考虑将这段实现代码抽取成一个共性方法,而这个共性方法是不需要让别人使用的,因此用私有给隐藏起来,这就是Java 9增加私有方法的必然性
定义格式
格式1:private 返回值类型 方法名(参数列表) { }
范例1
private void show() {
}
格式2:private static 返回值类型 方法名(参数列表) { }
范例2
private static void method() {
}
注意事项
默认方法可以调用私有的静态方法和非静态方法
接口中的静态方法只能调用静态方法
//接口
public interface Inter {
public default void start() {
System.out.println(“start方法执行了…”);
log();
}
public default void end() {
System.out.println(“end方法执行了…”);
log();
}
private void log(){
System.out.println(“日志记录 ( 模拟 )”);
}
private static void check(){
System.out.println(“权限校验 ( 模拟 )”);
}
public static void open() {
check();
System.out.println(“open方法执行了”);
}
public static void close(){
check();
System.out.println(“close方法执行了”);
}
}
class InterImpl implements Inter {
}
public class TestInterface {
public static void main(String[] args) {
InterImpl ii = new InterImpl();
ii.start();
ii.end();
Inter.open();
Inter.close();
}
}
接口的使用思路:
如果发现一个类中所有的方法都是抽象方法,那么就可以将该类,改进为一个接口;
涉及到了接口大面积更新方法,而不想去修改每一个实现类,就可以将更新的方法,定义为带有方法体的默认方法;
希望默认方法调用的更加简洁,可以考虑设计为static静态方法(去掉default关键字);
默认方法中出现了重复代码,可以考虑抽取出一个私有方法(去掉default关键字)
7. 类和接口的关系
问题:
1.一个类的父类和实现的接口有相同的方法,那么该类调用这个方法,会调用谁的?
2.如果一个接口的两个父接口存在相同的默认方法,子接口需要做什么处理吗?
类与类的关系
继承关系,只能单继承,但是可以多层继承
类与接口的关系
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
接口与接口的关系
继承关系,可以单继承,也可以多继承
注意事项:
如果一个类的父类和所实现的接口中有相同的方法,默认调用的是父类的方法
如果两个接口中有同名的默认方法,其实现类或子接口都必须重写该方法
代码练习:
/**
- 目标:掌握接口和接口、类和接口之间的关系
- 1.定义接口Inter1和Inter2,在里面分别定义抽象方法method1和默认方法method2
- 2.定义一个接口继承Inter1和Inter2,观察效果
- 3.定义一个Fu类,在类中定义一个method2方法
- 4.定义一个Zi类,继承Fu类,并且实现Inter1接口,重写相应方法
- 5.在测试类中创建Zi类对象,调用method2方法,观察效果
- 6.定义一个Son类,同时实现Inter1和Inter2,观察效果
*/