1.final
【1】修饰变量:
(代码分析)
package com.mxdx9;
/**
* @Auther:雨天_
* @Date: 2022/4/20 - 04 - 20 - 9:39
* @Descroption: com.mxdx9
* @version:1.0
*/
public class Test {
//这是一个main方法
public static void main(String[] args) {
//第一种情况
//final修饰一个变量,变量的值不可以改变,这个变量也变成了一个字符常量,规定:修饰的名称大写
final int D = 20;//final修饰基本数据类型
//D = 90;报错,不可以修改值
//第二种情况
final Cat c = new Cat();//final修饰引用数据类型,地址值不可以改变
//c = new Cat();----->地址值不可以更改
//c对象的属性依然可以改变
c.age = 19;
c.weight = 9;
//第三种情况
final Cat c2 = new Cat();
a(c2);
//第四种情况
b(c2);
}
public static void a(Cat c){
c = new Cat();
}
public static void b(final Cat c){//c被final修饰,指向不可以改变
//c = new Cat();
}
}
package com.mxdx9;
public class Cat {
int age;
double weight;
}
【2】修饰方法:
final 修饰方法,这个方法不能被该类的子类重写
【3】修饰类:
final 修饰类,代表没有子类,该类不可以被继承。
类被 final 修饰,里面的类没有必要被 final 修饰(final 可以省略不写)
【4】案例:JDK 提供的 Math 类:由源码得;
(1)使用Math 类的时候无需导包,直接使用即可:
(2)Math 没有子类,不能被其他类继承
(3)里面的属性全部被 final 修饰,方法也是被 final 修饰,只不过省略不写
原因:子类没有必要进行重写
(4)外界不可以创建对象
Math m = new Math();
(5)Math 类中的所有属性,方法都被 static 修饰,则不能通过创建对象去调用,
用 类名. 方法名 类名. 属性名 去调用
2.抽象类和抽象方法
【1】抽象类和抽象方法的关系
抽象类中可以定义0-n个抽象方法
【2】抽象类的作用:
在抽象类中定义抽象方法,目的是为子类提供通用的模板。
子类在定义的模板的基础上进行开发,先重写父类的抽象方法,然后可以扩展子类,抽象类避免了子类设计的随意性。通过抽象类,对子类进行某种程度上的限制。
【3】代码示例;
package com.mxdx9;
/**
* @Auther:雨天_
* @Date: 2022/4/20 - 04 - 20 - 12:07
* @Descroption: com.mxdx9
* @version:1.0
*/
//4.一个类中如果有抽象方法,那么这个类也要变成抽象类
//5.一个抽象类中可以有0-n个抽象方法
public abstract class Person {
//1.在一个类中,有一类方法,子类对这个方法满意,无需重写,直接使用
public void say(){
System.out.println("我会说话");
}
//2.在一个类中,会有一类方法,子类对这个方法不会满意,会进行重写
//3,一个方法的方法体去掉,被 abstract 修饰,那么这个方法就变成了一个抽象方法
public abstract void sleep();
public abstract void study();
}
//6.抽象类可以被其他类继承:
//7.一个类继承一个抽象类,那么这个类可以变成一个抽象类
//8.一般子类不会 + abstract 修饰,一般会让子类重写父类中的抽象方法
//9,子类重写抽象类,必须重写全部的抽象方法
//10.子类未重写全部的抽象方法,子类也可变成一个抽象类
class Student extends Person{
@Override
public void sleep() {
System.out.println("我喜欢在家里睡觉");
}
@Override
public void study() {
System.out.println("我喜欢学习");
}
}
class Demo{
//这是一个main方法
public static void main(String[] args) {
//11。创建抽象类的对象:----->抽象类不可以创建对象
//Person p = new Person();
//12.创建子类对象:
Student s = new Student();
s.sleep();
s.study();
s.say();
//13.多态的写法:父类引用指向子类对象
Person p = new Student();
p.say();
p.study();
p.sleep();
}
}
【4】例题:
(1)抽象类不能创建对象,那么抽象类中是否有构造器?
抽象类中一定有构造器。构造器的作用:给子类初始化对象的时候先用 super 调用父类的构造器。
(2)抽象类是否可以被 final 修饰?
抽象类不能被 final 修饰,抽象类是为了给子类继承用的。一个类被 final 修饰就没有子类,不存在继承。
3.接口
【1】声明格式:
【2】代码示例:
package com.mxdx.Test01;
/*
1.类是类,接口是接口,是同一层次的概念
2.接口中没有构造器
3.接口如何声名:interface
4.JDK1.8之前,接口中只有两部分内收容
(1)常量:固定修饰符。public static final
(2)抽象方法:固定修饰符,public abstract
PS:修饰符可以省略不写,IDE会自动补全
*/
public interface TestInterface {
//常量
public static final int NUM = 10;
//抽象方法
public abstract void a();
public abstract void b(int num);
public abstract int c(String name);
}
interface TestInterface01{
void e();
void f();
}
class Person{
}
//5.类和接口的关系:实现关系。类实现接口
//6.一个类实现一个接口,这个实现类要重写接口中的全部的抽象方法
//7.没有全部重写抽象方法,那么这个类可以变成一个抽象类(一般不用)
/*8.java有单继承,还有多实现
一个类继承其他类,只能直接继承一个类
这个类实现接口,可以实现多个接口
*/
//9.先继承,再实现 extends Person implements TestInterface,TestInterface01
class Student extends Person implements TestInterface,TestInterface01{
@Override
public void a() {
System.out.println("------1");
}
@Override
public void b(int num) {
System.out.println("------2");
}
@Override
public int c(String name) {
return 10;
}
@Override
public void e() {
System.out.println("------3");
}
@Override
public void f() {
System.out.println("------4");
}
}
class Test{
//这是一个main方法
public static void main(String[] args) {
//10.接口不能创建对象
//TestInterface01 t = new TestInterface01();
TestInterface01 t = new Student();//接口指向实现类-----> 多态
//11.访问接口中的常量
System.out.println(TestInterface.NUM);
System.out.println(Student.NUM);
Student s = new Student();
System.out.println(s.NUM);
TestInterface t1 = new Student();
System.out.println(t1.NUM);
}
}
【3】接口的作用:
定义规则。与抽象类不同,它是接口不是类。
接口定义好规则,实现类负责实现。
【4】继承和实现
继承:子类对父类的继承
实现:实现类对接口的实现
【5】多态的应用场合:
(1)父类当做方法的形参,传入具体的子类的对象
(2)父类当做方法的返回值,返回的是具体的子类的对象
(3)接口当做方法的形参,传入具体的实现类的对象
(4)接口当作方法的返回值,返回的是具体的实现类的对象
【6】接口类和抽象类的区别:
附:
JDK1.8之前,接口中只有两部分内收容 (1)常量:固定修饰符。public static final (2)抽象方法:固定修饰符,public abstract
在JDK1.8之后,新增非抽象方法:
(1)被 public , default 修饰的非抽象方法
PS:1)default 修饰符必须加上,否则出错
2)在实现类中重写接口中的非抽象方法,default 修饰符必须不能加,否则出错。
package com.mxdx.Test01;
public interface TestInterface02 {
//常量
public static final int NUM = 10;
//抽象方法
public abstract void a();
//public abstract 修饰的非抽象方法
public default void b(){
System.out.println("TestInterface02-----b()----");
}
}
class Test1 implements TestInterface02{
public void c(){
//用接口中的 b 方法
b();//可以直接使用
TestInterface02.super.b();
}
@Override
public void a() {
System.out.println("重写了a方法");
}
@Override
public void b() {
}
}
(2)静态方法:
PS:1)Static 不可以省略不写
2)静态方法不能重写
package com.mxdx.Test01;
public interface TestInterface03 {
//常量
public static final int NUM = 10;
//抽象方法
public abstract void a();
//public default 修饰的非抽象方法
public default void b(){
System.out.println("-------TestInterface03----b()----");
}
//静态方法
public static void c(){
System.out.println("TestInterface03中的静态方法");
}
}
class Test3 implements TestInterface03{
@Override
public void a() {
System.out.println("重写了a方法");
}
public static void c(){
System.out.println("Test3中的静态方法");
}
}
class A{
//这是一个main方法
public static void main(String[] args) {
Test3 t3 = new Test3();
t3.c();
Test3.c();
TestInterface03.c();
}
}
问:为什么在接口中加入非抽象方法??
若接口中只能定义非抽象方法的话,那么修改接口中的内容对实现类的影响太大了,所有实现类都会受到影响。现今加入非抽象方法,对实现类没有影响,可直接调用。
附:内部类:
1.成员内部类:
(代码示例)
package com.mxdx.Test01;
/**
* 1.类的组成长:属性,方法,构造器,代码块(普通块,静态块,构造块,同步块),内部类
* 2.一个类TestOuter01的内部的类SubTest叫内部类,内部类:SubTest 外部类:TestOuter01
* 3.内部类:成员内部类(静态的,非静态的),局部内部类(位置;方法内,块内,构造器内)
* 4.成员内部类:其中含有属性,方法,构造器 修饰符:default,public,protected.private.final.
*/
public class TestOuter01 {
//成员内部类:
public class D{
int age = 20;
String name;
public void method(){
//内部类可以访问外部类的内容
//a();
int age = 30;
System.out.println(age);//30
System.out.println(this.age);//20
System.out.println(TestOuter01.this.age);
}
}
//静态成员内部类:
static class E{
public void method(){
//静态内部类中只能访问外部类中被static修饰的内容
//System.out.println(age);
//a();
}
}
//属性
int age = 10;
//局部变量在方法中或者块中放置
//方法
public void a(){
System.out.println("这是a方法");
{
System.out.println("这是一个普通块");
class B{
}
}
class A{
}
//7.外部类想访问内部类的东西,需要创建内部类的对象然后调用
D d = new D();//new D();出错,静态的不能访问非静态的东西
System.out.println(d.name);
d.method();
}
static {
System.out.println("这是一个静态块");
}
{
System.out.println("这是一个构造块");
}
//构造器
public TestOuter01(){
class C{
}
}
public TestOuter01(int age){
this.age = age;
}
}
class Demo{
//这是一个main方法
public static void main(String[] args) {
//创建外部类的对象
TestOuter01 t1 = new TestOuter01();
t1.a();
//创建内部类的对象
//静态的成员内部类创建对象
TestOuter01.E e = new TestOuter01.E();
//非静态成员内部类创建对象
//错误:TestOuter01.D d = new TestOuter01.D();
TestOuter01 t = new TestOuter01();
TestOuter01.D d =t.new D();
}
}
2.局部内部类:
(代码示例)
package com.mxdx.Test02;
public class TestOuter {
//这是一个main方法
public void method(){
//1.在局部内部类中访问的变量必须是被final修饰的
final int num = 10;
class A{
public void a(){//若要在a中访问上面的num,上面的变量必须是被final修饰的
//num = 20;若被final修饰,这个值便不能改变
System.out.println(num);
}
}
}
//2.如果B在整个项目中只使用一次,那么就没有必要单独创建一个B类,使用内部类就可以
public Comparable method2() {
class B implements Comparable {
@Override
public int compareTo(Object o) {
return 10;
}
}
return new B();
}
public Comparable method3(){
//3.匿名内部类
return new Comparable() {
@Override
public int compareTo(Object o) {
return 120;
}
};
}
public void Test(){
Comparable com = new Comparable() {
@Override
public int compareTo(Object o) {
return 120;
}
};
System.out.println(com.compareTo("abc"));
}
}
4.项目
【1】项目结构分析
【2】父类子类创建:
package com.mxdx.Test03;
public class Pizza {
// 属性
private String name;//名称
private int size;//大小
private int price;//价格
//方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSize() {
return size;
}
public void setSixe(int size) {
this.size = size;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
//展示披萨信息
public String showPizza(){
return "披萨的名字是:"+name+",\n披萨的大小是:"+size+"寸,\n披萨的价格是"+price+"元";
}
//构造器
public Pizza(){
}
public Pizza(String name, int size, int price) {
this.name = name;
this.size = size;
this.price = price;
}
}
package com.mxdx.Test03;
public class FruitsPizza extends Pizza{
//属性
private String burdening;
public String getBurdening() {
return burdening;
}
public void setBurdening(String burdening) {
this.burdening = burdening;
}
//构造器
public FruitsPizza(){
}
public FruitsPizza(String name, int size, int price, String burdening) {
super(name, size, price);
this.burdening = burdening;
}
//重写父类的showPizza方法:
@Override
public String showPizza() {
return super.showPizza()+"\n 需要加入的水果是:"+burdening;
}
}
package com.mxdx.Test03;
public class BaconPizza extends Pizza{
//属性:
private int weight;
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
//构造器:
public BaconPizza(){
}
public BaconPizza(String name, int size, int price, int weight) {
super(name, size, price);
this.weight = weight;
}
//重写父类的showPizza方法:
@Override
public String showPizza() {
return super.showPizza()+"\n 培根的克数是:"+weight+"克";
}
}
【3】测试类逻辑以及创建
package com.mxdx.Test03;
import java.util.Scanner;
public class Test {
//这是一个main方法
public static void main(String[] args) {
//选择
Scanner sc = new Scanner(System.in);
System.out.println("请选择你要购买的披萨。(1.培根披萨 2. 水果披萨):");
int choice = sc.nextInt();//选择
switch (choice) {
case 1:
{
System.out.println("请录入培根的克数:");
int weight = sc.nextInt();
System.out.println("请录入披萨的大小:");
int size = sc.nextInt();
System.out.println("请录入披萨的价格:");
int price = sc.nextInt();
//将录入的信息封装为培根披萨的对象:
BaconPizza bp = new BaconPizza("培根披萨",size,price,weight);
System.out.println(bp.showPizza());
}
break;
case 2:
{
System.out.println("请录入想加入的水果:");
String Burdening = sc.next();
System.out.println("请录入披萨的大小:");
int size = sc.nextInt();
System.out.println("请录入披萨的价格:");
int price = sc.nextInt();
//将录入的信息封装为水果披萨的对象:
FruitsPizza fp = new FruitsPizza("水果披萨",size,price,Burdening);
System.out.println(fp.showPizza());
}
break;
}
}
}
【4】工厂类的提取:
package com.mxdx.Test03;
import java.util.Scanner;
public class Test {
//这是一个main方法
public static void main(String[] args) {
//选择
Scanner sc = new Scanner(System.in);
System.out.println("请选择你要购买的披萨。(1.培根披萨 2. 水果披萨):");
int choice = sc.nextInt();//选择
//通过工厂获取披萨:
Pizza pizza = PizzaStore.getPizza(choice);
System.out.println(pizza.showPizza());
}
}
package com.mxdx.Test03;
import java.util.Scanner;
public class PizzaStore {
public static Pizza getPizza(int choice){
Scanner sc = new Scanner(System.in);
Pizza p = null;
switch (choice) {
case 1:
{
System.out.println("请录入培根的克数:");
int weight = sc.nextInt();
System.out.println("请录入披萨的大小:");
int size = sc.nextInt();
System.out.println("请录入披萨的价格:");
int price = sc.nextInt();
//将录入的信息封装为培根披萨的对象:
BaconPizza bp = new BaconPizza("培根披萨",size,price,weight);
p = bp;
}
break;
case 2:
{
System.out.println("请录入想加入的水果:");
String Burdening = sc.next();
System.out.println("请录入披萨的大小:");
int size = sc.nextInt();
System.out.println("请录入披萨的价格:");
int price = sc.nextInt();
//将录入的信息封装为水果披萨的对象:
FruitsPizza fp = new FruitsPizza("水果披萨",size,price,Burdening);
p = fp;
}
break;
}
return p;
}
}