1 static
1.1 概念
是java中的一个关键字
用于修饰成员(成员变量和成员方法)
1.2 特点
- 随着类的加载而加载
- 只加载一次,就会一直存在,直到类消失就一起消失了
- 优先于对象加载
- 被所有对象所共享
- 可以<mark>直接被类名调用</mark>
1.3 练习1:入门案例
创建day07工程
创建cn.tedu.staticdemo包
创建Test1_Static.java
package cn.tedu.staticdemo;
//这个类用来测试static的使用
public class Test1_Static {
public static void main(String[] args) {
//1、随着类的加载而加载,没有也可以
//2、静态资源可以被类名直接调用
System.out.println(Person.name);
//TODO 创建Person对象测试
Person p = new Person();
p.name="rose";
p.eat();
System.out.println(p.name);
Person p2 = new Person();
//3、静态资源在所有对象间都是共享的,p修改后,p2能够看到改后的数据
System.out.println(p2.name);
}
}
//创建Person类
class Person{
static String name = "jack";
public void eat() {
System.out.println("正在吃饭");
}
}
1.4 [了解]静态内存图
1.5 练习2:静态调用关系
package cn.tedu.staticdemo;
//这个类用来测试static的调用关系
//总结:1、静态只能 调 静态
public class Test2_Static2 {
public static void main(String[] args) {}
}
//创建Animal类
class Animal{
//普通资源 -- 调用啥都行(静态/非静态)
String name;
public void eat() {
//普通资源 调用 静态资源 -- 能
sleep();
//普通资源 调用 普通资源 -- 能
System.out.println(name);
System.out.println("正在吃饭");
}
//静态资源 -- 只能调用 静态资源
static int age;
static public void sleep() {
//静态资源 调用 普通资源 -- 不能
// System.out.println(name);
//静态资源 调用 静态资源 -- 能
System.out.println(age);
System.out.println("正在睡觉");
}
}
2 静态代码块、构造代码块、局部代码块
static {
}
- 静态代码块:在类加载时就加载,并且<mark>只被加载一次</mark>,一般用于项目的初始化
- 构造代码块:在创建对象时会自动调用,每次创建对象都会被调用
- 局部代码块:方法里的代码块
package cn.tedu.staticdemo;
//测试三种代码块的执行顺序
//1、 静态代码块:在类加载时就加载,并且只被加载一次,一般用于项目的初始化
//2、 构造代码块:在创建对象时会自动调用,每次创建对象都会被调用
//3、 局部代码块:方法里的代码块
public class Test3_Block {
public static void main(String[] args) {
//创建Teacher对象
Teacher t = new Teacher();
Teacher t2 = new Teacher();
//t: 静态代码块
//t: 构造代码块
//t: 构造方法
//t2: 构造代码块
//t2: 构造方法
t.eat();//局部代码块
t.eat();//局部代码块
}
}
//创建类
class Teacher{
//构造代码块:创建对象时用,常用于提取构造方法的共性
{
System.out.println("构造代码块");
}
//构造方法,常用于创建对象
public Teacher() {
System.out.println("构造方法");
}
//静态代码块:类加载就用,常用于功能的初始化,只加载一次!
static {
System.out.println("静态代码块");
}
public void eat() {
//局部代码块:方法调用时才用,常用于控制变量的范围
{
System.out.println("局部代码块");
}
}
}
3 final
3.1 概念
- 是java提供的一个关键字
- final是最终的意思
- final可以修饰类,方法,成员变量
初衷是因为:java出现了继承后,子类可以更改父类的功能,当父类功能不许子类改变时可以利用final关键字修饰父类。
3.2 特点
- <mark>被final修饰的类,不能被继承</mark>
- <mark>被final修饰的方法,不能被重写</mark>
- 被final修饰的变量是个常量,不能被改变
- 常量的定义形式:final 数据类型 常量名 = 值
3.3 入门案例
package cn.tedu.finaldemo;
//这个类用来测试final关键字
public class Test4_Final {
public static void main(String[] args) {
//创建父类对象测试
Fu f = new Fu();
f.age=20;
}
}
//创建父类
//1、final修饰的类,不能被继承
//final class Fu{
class Fu{
//2、final修饰的变量,值不能被修改,是个常量
// final int age = 10;
int age = 10;
//3、final修饰方法,不能被重写!
// final public void eat() {
public void eat() {
System.out.println("爸爸在吃饭");
}
}
//创建子类
class Zi extends Fu{
//重写
public void eat() {
System.out.println("儿子在吃饭");
}
}
4 多态 OOP
4.1 概念
多态指同一个实体同时具有多种形式。
它是面向对象程序设计(OOP)的一个重要特征。
主要是指同一个对象,在不同时刻,代表的对象不一样,指的是对象的多种形态。
好处是:可以把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,<mark>统一调用标准</mark>。
例子:狗有两种形态:狗和小动物
class Animal{
}
class Dog extends Animal{
}
class Test1{
main(){
Dog d = new Dog();//小狗是小狗
Animal a = new Dog();//小狗是小动物,多态
}
}
4.2 特点
- 多态的前提1是继承
- 多态的前提2要有方法的重写
- <mark>父类引用指向子类对象 如:Animal a = new Dog(); – 小到大,向上转型</mark>(非常常见)
- 多态中,编译看左边,运行看右边
4.3 入门案例
package cn.tedu.duotai;
//这个类用来测试多态的入门案例
public class Test5_Duotai {
public static void main(String[] args) {
//创建父类对象测试
Animal a = new Animal(); a.eat();//吃啥都行
//创建子类对象测试
Dog d = new Dog(); d.eat();//吃啥都行 -- 狗吃s(因为重写了)
//TODO 创建多态对象测试
Animal a2 = new Dog(); //1、父类引用 指向 子类对象 -- 向上造型 / 多态
//2、编译看左边,运行看右边
//编译看左边:只能,用父类的功能 -- 统一调用标准
//运行看右边:干活看子类,如果重写了,就用子类的实现
a2.eat();//狗吃s
a2.show();
}
}
//创建父类
class Animal{
public void eat() {
System.out.println("吃啥都行");
}
public void show() {
}
}
//创建子类
//前提:继承+重写
class Dog extends Animal{
//重写:方法声明一致
public void eat() {
System.out.println("狗吃s");
}
}
5 多态的好处
- 多态可以让我们不用关心某个对象到底是什么具体类型,就可以使用该对象的某些方法
- 提高了程序的扩展性和可维护性
class Animal{
eat(Animal a){}
//多态中,不关心具体的子类是哪种类型,子类都当做父类来看
}
class Cat extends Animal{
}
class Tiger extends Animal{
}
class Test1{
main(){
eat(c);
eat(d);
eat(t);
}
}
6 多态的成员使用
6.1 特点
- 成员变量:使用的是父类的
- 成员方法:由于存在重写现象所以使用的是子类的
- 静态成员:随着对象而存在,谁调用的就返回谁的
(理解了对象在堆里怎么存的,栈里怎么引用的,上面自然知道了)
6.2 测试
package cn.tedu.duotai;
//这个类用来测试多态的使用
public class Test6_Duotai2 {
public static void main(String[] args) {
/*//TODO 创建父类对象测试 Sharp s = new Sharp(); s.draw();//画个图形 System.out.println(s.line);//5 //TODO 创建子类对象测试 Circle c = new Circle(); c.draw();//画个图形 -- 画个圈圈(重写了...) System.out.println(c.line);//5 */
//TODO 创建多态对象测试
Sharp s2 = new Circle();
s2.draw();//画个圈圈,1、多态中的成员方法,运行看右边,用子类的(发生了重写)
System.out.println(s2.line);//5,2、多态中的成员变量,用父类的
System.out.println(s2.name);//Sharp,3、静态资源是随着类存在的,哪个类调用就是哪个类的
}
}
//创建父类
class Sharp{
int line = 5;
static String name="Sharp";
public void draw() {
System.out.println("画个图形");
}
}
//创建子类
class Circle extends Sharp{
int line = 10;
static String name="Circle";
//重写draw()
public void draw() {
System.out.println("画个圈圈");
}
}
7 常见修饰符
8 异常
8.1 概述
用来封装错误信息的对象。
组成结构:类型,提示,行号。
8.2 异常的继承结构
Throwable - 顶级父类
-- Error:系统错误,无法修复
-- Exception:可修复的错误
--RunTimeException
--ClassCastException
--ClassNotFoundException
8.3 异常处理
程序中遇到了异常,通常有两种处理方式: 捕获 或者向上 抛出 。
当调用了一个抛出异常的方法时,调用位置可以不做处理继续向上抛出也可以捕获异常。
8.4 测试
package cn.tedu.exception;
import java.util.InputMismatchException;
import java.util.Scanner;
//这个类用来测试异常的处理
//处理异常的解决方案:捕获 + 抛出
public class Test7_Exception {
public static void main(String[] args) throws Exception{
// method();// 异常的捕获
//method2抛出异常,main()可以捕获也可以继续抛出
method2();// 异常的抛出
}
// 异常的抛出:throws...异常类型1,异常类型2 或者 直接throws...Exception
// private static void method2() throws InputMismatchException,ArithmeticException{
private static void method2() throws Exception{
// 1、接收用户输入的两个整数a b
int a = new Scanner(System.in).nextInt();
int b = new Scanner(System.in).nextInt();
// 2、做除法运算
System.out.println(a / b);
}
// 异常的捕获:try....catch(异常类型 异常名){ }
private static void method() {
try {
// 1、接收用户输入的两个整数a b
int a = new Scanner(System.in).nextInt();
int b = new Scanner(System.in).nextInt();
// 2、做除法运算
System.out.println(a / b);
} catch (InputMismatchException e) {// 用来捕获输入数据类型不匹配的情况
System.out.println("请输入整数类型!");
} catch (ArithmeticException e) {// 用来捕获输入数据分母为0的情况
System.out.println("分母不能为0!");
} catch (Exception e) {// 多态!!不关心具体子类类型,把所有子类当父类来看,所以异常都能捕获
System.out.println("输入错误!!!");
}
}
}
9 拓展
9.1 向上转型和向下转型
在JAVA中,继承是一个重要的特征,通过extends关键字,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法来加以扩展。
<mark>在应用中就存在着两种转型方式,分别是:向上转型和向下转型。</mark>
比如:父类Parent,子类Child
<mark>向上转型:父类的引用指向子类对象Parent p=new Child();</mark>
说明:向上转型时,子类对象当成父类对象,只能调用父类的功能,如果子类重写了父类的方法就根据这个引用指向调用子类重写方法。
向下转型(较少):子类的引用的指向子类对象,过程中必须要采取到强制转型。
Parent p = new Child();//向上转型,此时,p是Parent类型
Child c = (Child)p;//此时,把Parent类型的p转成小类型Child
//其实,相当于创建了一个子类对象一样,可以用父类的,也可以用自己的
说明:向下转型时,是为了方便使用子类的特殊方法,也就是说当子类方法做了功能拓展,就可以直接使用子类功能。
9.2 静态变量和实例变量的区别
<mark>在语法定义上的区别</mark>:静态变量前要加static关键字,而实例变量前则不加。
<mark>在程序运行时的区别</mark>: 实例变量属于某个对象的属性, 必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。 静态变量不属于某个实例对象,而是属于类,所以<mark>也称为类变量</mark>, 只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
(另外,静态变量被多个相同的类共享,实例变量只属于实例的类本身)