- 在jdk8以前,类变量在方法区的静态域中
- 在jdk8以后,类变量在堆的class对象中
- 不管类变量在哪,共识是:
3.1. 类变量被同一个类的所有对象所共享(不同存储地方不影响对它的使用)
3.2. 类变量在类加载时就生成了
3.3 类变量是随着类加载而创建,所以即使没有创建对象实例也能访问
不创建实例,也能调用类的方法(方法中不涉及任何和对象相关的成员 或 通用的方法)
- main方法中可以直接访问本类 中的静态成员
直接写name,hi()
- main方法中不可以直接访问本类 中的非静态成员
- 必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员
Main01 main01 = new Main01();
main01.cry();
前面讲的是在cmd命令行中传递参数,这里讲如何在idea中传参
① 第一步
② 第二步
③ 输出
- 静态代码块和普通代码块 啥时被执行
- 静态代码块和普通代码块 执行的顺序
- 执行顺序的原因
- 综合:继承关系时静态[代码块和属性初始化]、普通、构造方法的综合调用顺序
- 静态代码块 只能访问静态方法和变量,普通代码块 可以访问任意
解读
解读一个类中的调用顺序:
解读调用顺序的原因分析:
解读:
叫饿汉式是因为:在类加载时就创建了单例对象,即使不使用,这个对象仍存在,显得很着急,所以叫饿汉
解读三部曲:
- 如果没将构造器私有化,则可以new好几个对象
private GirlFriend(String name){---}
- 若构造器私有化,则不能在外部创建对象,只能在类的内部创建私有对象
private GirlFriend gf = new GirlFriend("小红红")
- 外部不能访问这个私有对象
- 所以必须在类中提供一个公共的static方法,返回gf对象(为了能在静态方法中 返回gf对象,需要将其修饰为static)
public static GirlFriend getInstance(){return gf;}
- 获取对象
GirlFriend instance = GirlFriend.getInstance();
懒汉式 只有在对象使用getInstance时,才返回单例对象,后面再调用时,会返回上次创建的单例对象,从而实现单例模式
三部曲
- 一般来说,抽象类会被继承,由它的子类来实现抽象方法
- 抽象方法没有方法体
- 一个类中有抽象方法,则该类一定是抽象类
引出的过程及设计模式讲解
args.length.for 然后回车
生成:
for (int i = 0; i < args.length; i++) {
}
- 写一个接口usb
- 写两个类(phone和camera)实现接口
- 写一个类(computer)使用该接口(接口作为形参传入)
① 快捷键:alt+enter 快速把要实现的方法写出来
② 接口中的方法默认是public abstract;
① 一个类可以实现多个接口:
class A implement IB,IC{}
Java是单继承的,一个类只能继承一个类,但可以实现多个接口
② 接口不能继承其他类,但可以继承多个别的接口
③ 接口中的属性默认是public static final
也就是接口中属性 不能被修改,能直接用接口名访问
① 继承是is a的关系,小猴子继承老猴子,所以小猴子天生就会爬树(拥有全部父类属性和方法)
- java是单继承的,小猴子不能同时继承鸟,鱼
- 要想实现别的功能,可以通过 实现接口
② 小猴子要游泳,则要实现接口中的方法
③ 小猴子要飞翔,则要实现接口中的方法
④ 所以,接口(like a) 可以简单的看作是 对继承的一种补充
public class Excise {
public static void main(String[] args) {
LittleMoney littleMoney = new LittleMoney("悟空");
//继承父类的爬树
littleMoney.club();
//实现Fish接口的方法
littleMoney.swimming();
//实现Bird接口的方法
littleMoney.flying();
}
}
class Money {
private String name;
public Money(String name) {
this.name = name;
}
public void club() {
System.out.println(name + "会爬树");
}
public String getName() {
return name;
}
}
//继承
class LittleMoney extends Money implements Fish, Bird {
public LittleMoney(String name) {
super(name);
}
//实现接口中的方法
@Override
public void swimming() {
System.out.println(getName() + "通过学习,学会了游泳...");
}
@Override
public void flying() {
System.out.println(getName() + "通过学习,学会了飞翔...");
}
}
//接口
interface Fish {
void swimming();
}
interface Bird {
void flying();
}
接口的多态传递
- 如果IG 继承了IH 接口,而Teacher 类实现了 IG接口
- 那么,实际上相当于Teacher 类也实现了IH 接口
- 这就是接口多态传递
内部类是重点,也是难点,后面看源码有很多内部类
类的五大成员
① 位置:方法或代码块中
- 相当于局部变量(局部变量不能加访问修饰符)
- 可以直接访问全局变量(包含私有的)
② 作用域:仅在定义它的方法或代码块中
- 外部
- 外部其他类不能访问局部内部类
③本质:本质仍是一个类
① 这个内部类就是Outer04$1,直接在创建时写上类中的内容
new 接口(){ 实现方法 }
② 就相当于new Tiger(),然后再写tiger类实现IA 接口,再写实现的方法
tiger对象接收了匿名类的地址,可以使用很多次,
但是Outer04$1这个类只能使用一次(不能再调用)
- 创建继承普通类的匿名内部类
new Father("jack"){//内容};
1.1 (“jack”)参数列表会传递给 构造器- 创建继承抽象的匿名内部类
new Animal(){//实现抽象类方法};
- 创建实现接口的匿名内部类
new IA(){//实现接口方法};
- 涉及到 继承,多态,动态绑定,内部类
- 匿名内部类当作实参直接传递,简洁高效
public class Excise {
public static void main(String[] args) {
//匿名内部类当作实参直接传递,简洁高效
m(new IA() {
@Override
public void show() {
System.out.println("匿名内部类中重写接口的show方法");
}
});
//传统方法
Picture picture = new Picture();
m(picture);
}
//静态方法,形参是接口类型
public static void m(IA ia){
ia.show();
}
}
//接口
interface IA{
void show();
}
//传统方法-类-->实现接口 => 在编程领域称为硬编码
class Picture implements IA{
@Override
public void show() {
System.out.println("传统方法重写接口的show方法");
}
}
public class Excise {
public static void main(String[] args) {
CellPhone cellPhone = new CellPhone();
cellPhone.alarm(new Bell() {
@Override
public void ring() {
System.out.println("小懒猪起床了");
}
});
cellPhone.alarm(new Bell() {
@Override
public void ring() {
System.out.println("小伙伴上课了");
}
});
}
}
interface Bell{
void ring();
}
class CellPhone{
public void alarm(Bell bell){
bell.ring();
}
}
访问外部类成员,比如属性name,则
new Outer().name
对于成员内部类也是一样的new Outer().new Inner();
普通成员不能通过类名直接访问,得先创建外部类对象,再通过外部类对象创建成员内部类对象当然是不能写成new new Outer().Inner()
外部其他类访问成员内部类的两种方法
/**
* @author 王胖子
* @version 1.0
*/
public class Excise {
public static void main(String[] args) {
System.out.println(Frock.getNextNum());//100100
System.out.println(Frock.getNextNum());//100200
Frock frock1 = new Frock();
Frock frock2 = new Frock();
Frock frock3 = new Frock();
System.out.println(frock1.getSeriaNumber());//100300
System.out.println(frock2.getSeriaNumber());//100400
System.out.println(frock3.getSeriaNumber());//100500
}
}
class Frock {
private static int currentNum = 100000;//出场序列号的起始值
private int seriaNumber;
public Frock() {
this.seriaNumber = getNextNum();
}
public static int getNextNum() {//生成上衣唯一序列号的方法
currentNum += 100;
return currentNum;
}
public int getSeriaNumber() {
return seriaNumber;
}
}
匿名内部类最经典的用法就是作为参数
- 普通传参方法:先创建一个实现了ICalculate接口的类,再创建该类的对象,把该对象作为参数传入test方法中
- 匿名内部类方法:直接传入一个实现了ICalculate接口的匿名内部类即可
该匿名内部类可以灵活的实现work,完成不同的计算任务
/**
* @author 王胖子
* @version 1.0
*/
public class Excise {
public static void main(String[] args) {
//匿名内部类省去了 创建类实现接口效率低的麻烦
/*
匿名内部类是实现了接口的类,同时也是一个对象
编译类型是ICalculate(),运行类型是匿名内部类
new ICalculate() {
@Override
public double work(double n1, double n2) {
return n1 +n2;
}
*/
CellPhone cellPhone = new CellPhone();
cellPhone.testWork(new ICalculate() {
@Override
public double work(double n1, double n2) {
return n1 + n2;
}
}, 10, 20);
}
}
//接口类
interface ICalculate {
//完成计算(用匿名内部类来实现)
public double work(double n1, double n2);
}
class CellPhone {
//解读:
//普通传参方法:先创建一个实现了ICalculate接口的类,再创建该类的对象,把该对象作为参数传入test方法中
//匿名内部类方法:直接传入一个实现了ICalculate接口的匿名内部类即可
//该匿名内部类可以灵活的实现work,完成不同的计算任务
public void testWork(ICalculate iCalculate, double n1, double n2) {
double result = iCalculate.work(n1, n2);//动态绑定运行类型(上面的匿名内部类)
System.out.println("计算后的结果是 = " + result);
}
}
/**
* @author 王胖子
* @version 1.0
*/
public class Excise {
public static void main(String[] args) {
A a = new A();
a.method();
}
}
class A {
private String NAME = "小瘦子";
public void method() {
//局部内部类定义在方法或代码块中
//使用:在类中创建内部类对象,调用内部类方法
//可以直接访问外部类内容(包括私有的)
//当内部类和外部类的属性重名时 可以通过外部类.this.属性名来访问外部类属性
class B {
private final String NAME = "小胖子";
void show() {
System.out.println("B类中的NAME = " + NAME + "\n" + "A类中的name = " + A.this.NAME);
}
}
B b = new B();
b.show();
}
}
/**
* @author 王胖子
* @version 1.0
*/
public class Excise {
public static void main(String[] args) {
Person person = new Person("唐僧", new Horse());
person.common();
person.passRiver();
person.passRiver();
}
}
//抽象产品接口
interface Vehicles {
public void work();
}
//具体产品类
class Horse implements Vehicles {
@Override
public void work() {
System.out.println("一般情况,用马走");
}
}
class Boat implements Vehicles {
@Override
public void work() {
System.out.println("过河时,用船走");
}
}
//工厂类
class Factory {
//方法定义为静态
//马只有一匹,用单例设计模式-饿汉式
private Horse horse = new Horse();
private Factory() {
}
public static Vehicles getHorse() {
return new Horse();
}
public static Vehicles getBoat() {
return new Boat();
}
}
//人(整合)
class Person {
private String name;
private Vehicles vehicles;
public Person(String name, Vehicles vehicles) {
this.name = name;
this.vehicles = vehicles;
}
public void common() {
//如果vehicles的运行类型不是Horse,则用工厂类返回一个马对象
if (!(vehicles instanceof Horse)) {
vehicles = Factory.getHorse();
}
vehicles.work();
}
public void passRiver() {
//如果vehicles的运行类型不是Boat,则用工厂类返回一个船对象
if (!(vehicles instanceof Boat)) {
vehicles = Factory.getBoat();
}
vehicles.work();
}
}
- 类与成员内部类 体现类与类的包含关系
- 成员内部类 在外部其他类中使用可以调用外部类中的get方法获取内部类的对象
public Air getAir() {
return new Air();
}
/**
* @author 王胖子
* @version 1.0
*/
public class Excise {
public static void main(String[] args) {
//实例化不同的car对象
Car car = new Car(26);
car.getAir().flow();
Car car1 = new Car(41);
car1.getAir().flow();
Car car2 = new Car(41);
car2.getAir().flow();
}
}
class Car {
private double template;
public Car(double template) {
this.template = template;
}
//air 成员内部类
class Air {
public void flow() {
if (template > 40) {
System.out.println("温度大于40,吹冷风");
} else if (template < 0) {
System.out.println("温度小于0,吹热风");
} else {
System.out.println("温度正常,关闭空调");
}
}
}
public Air getAir() {
return new Air();
}
}