目录
2.如何将控制台获取的数据传给形参:String[] args?
3. 实例化子类对象时,涉及到父类、子类中静态代码块、非静态代码块、构造器的加载顺序:
一、static关键字:静态的
1.可以用来修饰的结构
主要用来修饰类的内部结构:属性、方法、代码块、内部类
2. static修饰属性:静态变量(或类变量)
2.1.属性
属性:是否使用static修饰,又分为:静态属性(静态变量) VS 非静态属性(实例变量)
实例变量:我们创建了类的多个对象,每个对象都独立的拥一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。
2.2. static修饰属性的其他说明
① 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用
② 静态变量的加载要早于对象的创建。
③ 由于类只会加载一次,则静态变量在内存中也只会存在一份,存在方法区的静态域中。
④ 类变量 实例变量
类 yes no
对象 yes yes
2.3 静态属性举例:
System.out---->静态的
Math.PI------>静态的
3.静态变量内存解析
4.static修饰方法:静态方法(或类方法)
① 随着类的加载而加载,可以通过“类.静态方法”的方式进行调用
② 静态方法 非静态方法
类 yes no
对象 yes yes
③ 静态方法中,只能调用静态的方法或属性
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
5. static的注意点
5.1 在静态的方法内,不能使用this关键字、super关键字
5.2 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。
6.如何判定属性和方法应该使用static关键字
6.1 关于属性
> 属性是可以被多个对象所共享的,不会随着对象的不同而不同。
>类中的常量也常常声明为static
6.2 关于方法
> 操作静态属性的方法,通常设置为static的。
> 工具类中的方法,习惯上声明为static的。 比如:Math、Arrays、Collections
7.使用举例
举例一:Arrays、Math、Collections等工具类
举例二:单例模式
举例三:class Circle{ private double radius; private int id;//自动赋值 public Circle() { id = init++; total++; } public Circle(double radius) { this(); this.radius = radius; // id = init++; // total++; } private static int total;//记录创建的圆的个数 private static int init = 1001;//static声明的属性被所的对象所共享 public double findArea() { return 3.14 * radius * radius; } public int getId() { return id; } public void setId(int id) { this.id = id; } public double getRadius() { return this.radius; } public void setRadius(double radius) { this.radius = radius; } public static int getTotal() { return total; } }
8.单例模式(Singleton)
8.1.设计模式
>理解:设计模式 是在大量的实践中总结和理论化之后优的代码结构、编程风格、 以及解决问题的思考方式。-------------------------------------------------------------------------------------------------------------------------->常用设计模式 ---23种经典的设计模式创建型模式,共5种:工厂方法模式、抽象工厂模式、 单例模式、建造者模式、原型模式
结构型模式:共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式
8.2. 要解决的问题:
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例
8.3.具体代码的实现
饿汉式
//饿汉式1
class Bank{
//1.私化类的构造器
private Bank() {
}
//2.内部常见类的对象
//4.要求此对象也必须声名为静态的
private static Bank instance = new Bank();
//3.提供公共的静态方法,返回类的对象
public static Bank getInstance() {
return instance;
}
}
//饿汉式2
class Order{
//1.私化类的构造器
private Order() {
}
//2.声明当前类对象,没初始化
//4.此对象也必须声名为static的
private static Order instance = null;
static{
instance = new Order();
}
//3.声明public、static的返回当前类对象的方法
public static Order getInstance() {
return instance;
}
}
懒汉式
class Order{
//1.私化类的构造器
private Order() {
}
//2.声明当前类对象,没初始化
//4.此对象也必须声名为static的
private static Order instance = null;
//3.声明public、static的返回当前类对象的方法
public synchronized static Order getInstance() {
if(instance == null) {
instance = new Order();
}
return instance;
}
}
8.4.饿汉式与懒汉式两种方式的对比
饿汉式:
坏处:对象加载时间过长。
好处:饿汉式是线程安全的
懒汉式:
好处:延迟对象的创建。
目前的写法坏处:线程不安全。----->到多线程内容时,再修改
二、main()方法
1.main()方法的使用说明
1. main()方法作为程序的入口
2. main()方法也是一个普通的静态方法
3. main()方法可以作为我们与控制台交互的方式。(之前,使用的Scanner)
2.如何将控制台获取的数据传给形参:String[] args?
运行时:java 类名 "Tom" "Jerry" "123" "true"
sysout(args[0]);//"Tom"
sysout(args[3]);//"true" ------>Boolean.parseBoolean(args[3]);
sysout(args[4]);//报异常
3.小结
小结:一叶知秋
public static void main(String[] args){
//方法体
}
权限修饰符:private 缺省 protected public ----->封装性
修饰符:static \ final \ abstract \ native
返回值类型:无返回值 / 有返回值 --->return
方法名:需要满足标识符命名的规则、规范:“见名知意”
形参列表:重载 vs 重写:参数的值传递机制:体现对象的多态性
main(){
Person p = new Man();//多态性
p.eat();
}
方法体:来体现方法的功能
三、类的成员之四:代码块(初始化块)
1.代码块的作用
用来初始化类、对象的信息
2.分类
分类:代码块要是使用修饰符,只能使用static
------------------------------------------------------------------------------------------------------------------
静态代码块 vs 非静态代码块
-------------------------------------------------------------------------------------------------------------------
静态代码块:
>内部可以输出语句
>随着类的加载而执行,而且只加载一次
>作用:初始化类的信息(如静态的属性
>如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
>静态代码块的执行要优先于非静态代码块
>静态代码块内只能调用静态的属性、静态的方法。不能调用非静态的结构-------------------------------------------------------------------------------------------------------
非静态代码块:
>内部可以输出语句
>随着对象的创建而执行
>每创建一个对象,就执行一次非静态代码块
>作用:可以在创建对象时,对对象的属性等进行初始化
>如果一个类中定义了多个非静态代码块,则按照声名的先后顺序执行
>非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法
3. 实例化子类对象时,涉及到父类、子类中静态代码块、非静态代码块、构造器的加载顺序:
由父及子,静态先行
举例一:LeafTest.java
package com.atguigu.java3; //总结:由父及子,静态先行 class Root{ static{ System.out.println("Root的静态初始化块"); } { System.out.println("Root的普通初始化块"); } public Root(){ System.out.println("Root的无参数的构造器"); } } class Mid extends Root{ static{ System.out.println("Mid的静态初始化块"); } { System.out.println("Mid的普通初始化块"); } public Mid(){ System.out.println("Mid的无参数的构造器"); } public Mid(String msg){ //通过this调用同一类中重载的构造器 this(); System.out.println("Mid的带参数构造器,其参数值:" + msg); } } class Leaf extends Mid{ static{ System.out.println("Leaf的静态初始化块"); } { System.out.println("Leaf的普通初始化块"); } public Leaf(){ //通过super调用父类中有一个字符串参数的构造器 super("尚硅谷"); System.out.println("Leaf的构造器"); } } public class LeafTest{ public static void main(String[] args){ new Leaf(); //new Leaf(); } }
举例二:Son.java
package com.atguigu.java3; class Father { static { System.out.println("11111111111"); } { System.out.println("22222222222"); } public Father() { System.out.println("33333333333"); } } public class Son extends Father { static { System.out.println("44444444444"); } { System.out.println("55555555555"); } public Son() { System.out.println("66666666666"); } public static void main(String[] args) { // 由父及子 静态先行 System.out.println("77777777777"); System.out.println("************************"); new Son(); System.out.println("************************"); new Son(); System.out.println("************************"); new Father(); } }
4.属性的赋值顺序
对属性可以赋值的位置
①默认初始化:系统默认值
②显式初始化:定义变量时直接赋值
③构造器中初始化
④了对象以后,可以通过“对象.属性”或"对象.方法"的方式,进行赋值
⑤在代码块中赋值
执行先后顺序 :① - ②/⑤ - ③ - ④②、⑤二者先声明的先执行
四、关键字:final(最终的)
1.可以用来修饰:
final可以用来修饰的结构:类、方法、变量
2.具体的:
2.1.final 用来修饰一个类
final 用来修饰一个类:此类不能被其它类所继承。
比如:String类、System类、StringBuffer类
2.2.final 用来修饰方法
final 用来修饰方法:表明此方法不可以被重写
比如:Object类中的getClass():获取当前对象所在的类
关键字native:调用的是c或c++,不再是Java了
2.3.final 用来修饰变量
final 用来修饰变量,此时的“变量”被称为一个常量
>final修饰属性:可以考虑赋值的位置:显式初始化、代码块中初始化、构造器中初始化
>final修饰局部变量:
尤其是使用final修饰形参时,表明此形参是一个常量,当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。static final 用来修饰属性:全局常量
五、关键字:abstract(抽象的)
1.修饰结构
可以用来修饰:类、方法
2.具体的:
2.1.abstract修饰类:抽象类
abstract修饰类:抽象类
> 此类不能实例化
> 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化化的全过程)
> 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作---->抽象的使用前提:继承性。
2.2. abstract修饰方法:抽象方法
abstract修饰方法:抽象方法
>抽象方法只方法的声明,没方法体
>包含抽象方法的类一定是一个抽象类。反之,抽象类中可以没有抽象方法。
>若子类重写了父类中的所的抽象方法后,此子类方可实例化
若子类没重写父类中所的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰
3.注意点:
1.abstract不能用来修饰:属性、构造器等结构
2.abstract不能用来修饰私方法、静态方法、final的方法、final类
>不能修饰私方法原因:abstract修饰的抽象方法,需要在子类中继承时重写,private修饰的私方法,不能重写
>不能修饰静态方法原因:静态方法只能重载,不能被重写。
>final修饰的方法不能被重写,final修饰的类不能被继承
4.abstract的应用举例:
4.1.举例一
4.2. 举例二
abstract class GeometricObject{ public abstract double findArea(); } class Circle extends GeometricObject{ private double radius; public double findArea(){ return 3.14*radius*radius; } }
4.3.举例三
IO流中涉及到的抽象类:InputStream/OutputStream/Reader / Writer。在其内部定义了抽象的read()、write()方法。
5.模板方法的设计模式
5.1. 解决的问题
在软件开发中实现一个算法时,整体步骤很固定、通用,
这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽
象出来,供不同子类实现。这就是一种模板模式。
5.2. 举例
//一个模板: abstract class Template{ //计算某段代码执行所需花费的时间 public void spendTime() { long start = System.currentTimeMillis(); code();//不确定的部分、易变的部分 long end = System.currentTimeMillis(); System.out.println("花费的时间为:"+(end - start)); } public abstract void code(); } class SubTemplate extends Template{ @Override public void code() { for(int i = 2;i <= 1000;i++) { boolean isFlag = true; for(int j = 2;i <= Math.sqrt(i);j++) { if(i % j == 0) { isFlag = false; break; } } if(isFlag) { System.out.println(i); } } } public void hello() { System.out.println("HEllO"); } }
5.3. 应用场景
6.抽象类的匿名子类
父类Person,抽象方法public abstract void eat();public abstract void breath();
---->子类Woeker,子类Student
创建一个测试类PersonTest,创建两个静态方法
public static void method1(Person p) {
p.eat();
p.breath();
}
public static void method(Student s) {
}
6.1.匿名对象,非匿名子类
method(new Student());//new Student()-->直接new,不进行变量的命名,匿名对象
6.2.非匿名对象,非匿名子类
Worker woeker = new Worker();
method1(woeker);//非匿名的类,非匿名的对象
6.3.非匿名对象,匿名子类
//创建类一匿名子类的对象:p
//如同创建了一个没有名字的子类,非匿名对象,继承Person()父类
Person p = new Person() {
//重写的抽象方法
@Override
public void eat() {
System.out.println("吃东西");
}@Override
public void breath() {
System.out.println("好好呼吸");
}
};
method1(p);//方法
6.4.匿名对象,匿名子类
//创建匿名子类的匿名对象
method1(new Person() {@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("吃好吃的东西");
}@Override
public void breath() {
// TODO Auto-generated method stub
System.out.println("好好呼吸");
}
});
六、关键字:interface(接口)
1.什么是接口
>接口就是规范,定义的是一组规则,体现了现实世界中“如果你是 / 要 ... 则必须能 ... ”的思想。 继承是一个 " 是不是 " 的关系,而接口实现则是 " 能不能 "的关系。> 接口的本质是契约,标准,规范 ,就像我们的法律一样。制定好后大家都要遵守。>接口 ( interface ) 是 抽象方法 和 常量值 定义的集合。
2.使用说明
1.接口使用interface来定义
2.Java中,接口和类是并列的两个结构
3.如何定义接口:定义接口中的成员
3.1 JDK7以前:只能定义全局常量和抽象方法
>全局常量:public static final的,但是书写时,可以省略不写
>抽象方法:public abstract的,但是书写时,可以省略不写
3.2 JDK8:除了定义全局常量和抽象方法外,还可以定义静态方法、默认方法
见CompareA.java
4.接口中是不能声明构造器的!意味着接口不可以实例化
5.Java开发中,接口都通过类去实现(implements)的方式去使用
如果实现类覆盖了接口中的所抽象方法,则此实现类就可以实例化;实现类继承父类时,extends要写在接口implements之前。
如果实现类没覆盖接口中所的抽象方法,则此实现类仍为一个抽象类
6.Java类可以实现多个接口 ----->弥补了Java单继承性的局限性:eg String类,Inerger类
格式:class AA extends BB implements CC,DD,EE{}
7.接口与接口之间可以继承,而且可以多继承
类与类之间,子类与父类之间是单继承关系
类与接口之间,是实现关系
---------------------------------------------------------------------------------------------------------------------
8.接口具体使用,体现多态性
9.接口,实际上可以看作是一种规范10.开发中,体会面向接口编程!
注:接口中的抽象方法的格式:
//接口中定义的抽象方法的语法格式
//第一种
public abstract void write();
//第二种
public void write();
//第三种
abstract String name();
//第四种
void show();
//只要不加大括号就不为错,就是抽象方法,仅限于接口中这样写;
3.面试题:抽象类与接口哪些异同?
接口和抽象类都不能实例化,都需要被继承
抽象类可以声明构造器,接口不能声明构造器。抽象类是单继承,接口是多继承
>抽象类被继承时一个子类只能继承一个抽象类,接口可以一次性继承多个。
定义方式不一样,实现方式不一样
>抽象类abstract 继承extends
>接口interface 实现implements抽象类中可以有非抽象方法,接口中只能定义抽象方法(JDK7版本之前)。
>JDK8 接口更像是一个抽象类
接口更像是一个模板。
4.举例
4.1.USB接口
//接口基本的使用 class Computer{ public void transferDate(USB usb) {//多态性,//USB usb = new Flash(); usb.start(); System.out.println("具体传输数据的细节"); usb.stop(); } } interface USB{ //定义长、宽、最大最小的传输速度等 void start(); void stop(); } class Flash implements USB{ @Override public void start() { System.out.println("U盘开启工作"); } @Override public void stop() { System.out.println("U盘结束工作"); } } class Printer implements USB{ @Override public void start() { System.out.println("打印机开始工作"); } @Override public void stop() { System.out.println("打印机结束工作"); } }
4.2体会:
1.接口使用上也满足多态性
2.接口,实际上就是定义了规范
3.开发中,体会面向接口编程!
4.3 创建了接口的匿名实现类的匿名对象
Computer com = new Computer(); //1.创建了接口的非匿名实现类的非匿名对象 Flash flash = new Flash(); com.transferDate(flash); //2.创建了接口的非匿名实现类的匿名对象 com.transferDate(new Flash()); //3.创建接口的匿名实现类的非匿名对象 USB phone = new USB() { @Override public void start() { System.out.println("手机开始工作"); } @Override public void stop() { System.out.println("手机结束工作"); } }; com.transferDate(phone); //4.创建了接口的匿名实现类的匿名对象 com.transferDate(new USB() { @Override public void start() { System.out.println("mp3开始工作"); } @Override public void stop() { System.out.println("mp3结束工作"); } });
5. 面向接口编程的思想
面向接口编程:我们在应用程序中,调用的结构都是JDBC中定义的接口,
数据库厂商的API。
6.Java8中关于接口的新规范
知识点1:接口中定义的静态方法只能通过接口来调用。
知识点2:通过实现类的对象,可以调用接口中的默认方法。
如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
知识点3:如果子类(或实现类)继承父类和实现的接口中声名类同名同参的方法,
那么子类在没重写此方法的情况下,默认调用的是父类中的同名同参数的方法 --->类优先原则
知识点4:如果实现类实现了多个接口,而这么多接口中定义了同名同参数的默认方法,
那么在实现类没重写此方法的情况下,报错。---->接口冲突
这就需要我们在实现类中重写此方法知识点5:如何在子类(或实现类的方法中调用父类、接口中被重写的方法
public interface CompareA { //静态方法 public static void menthod1() { System.out.println("CompareA:北京"); } //默认方法 public default void method2() { System.out.println("CompareA:上海"); } default void method3() { System.out.println("CompareA:上海"); } }
package com.atguigu.java8; public class SubclassTest { public static void main(String[] args) { SubClass s = new SubClass(); // s.method1(); //SubClass.method1(); //知识点1:接口中定义的静态方法只能通过接口来调用。 CompareA.menthod1(); //知识点2:通过实现类的对象,可以调用接口中的默认方法。 //如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法 s.method2(); //知识点3:如果子类(或实现类)继承父类和实现的接口中声名类同名同参的方法, //那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法 --->类优先原则 //知识点4:如果实现类实现了多个接口,而这么多接口中定义了同名同参数的默认方法, //那么在实现类没有重写此方法的情况下,报错。---->接口冲突 //这就需要我们在实现类中重写此方法 s.method3(); } } class SubClass extends SuperClass implements CompareA,CompareB{ public void method2() { System.out.println("SubClass,上海"); } public void method3() { System.out.println("SubClass:深圳"); } //知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法 public void myMethod() { method3();//调用自己定义的重写的方法 super.method3();//调用的是父类中声明的 //调用接口中的默认方法 CompareA.super.method3(); CompareB.super.method3(); } }
7.面试题:抽象类和接口的异同?
相同点:接口和抽象类都不能实例化;都需要被继承;都可以包含抽象方法;
不同点:
1)把抽象类和接口(jdk7,jdk8,jdk9)的定义、内部结构解释说明
2)Java中的继承关系
类:单继承 接口:多继承
类与接口关系:实现(implements)---->多实现抽象类可以声明构造器,接口不能声明构造器。
抽象类是单继承,接口是多继承
>抽象类被继承时一个子类只能继承一个抽象类,接口可以一次性继承多个。
定义方式不一样,实现方式不一样
>抽象类abstract 继承extends
>接口interface 实现implements抽象类中可以有非抽象方法,接口中只能定义抽象方法(JDK7版本之前)。
>JDK8 接口更像是一个抽象类
接口更像是一个模板。
接口和抽象类之间的对比
8.代理模式
1. 解决的问题
代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。
2. 举例
interface NetWork{ public void browse(); } //被代理类 class Server implements NetWork{ @Override public void browse() { System.out.println("真实的服务器访问网络"); } } //代理类 class ProxyServer implements NetWork{ private NetWork work; public ProxyServer(NetWork work) { this.work = work; } public void check() { System.out.println("联网之前的检查工作"); } @Override public void browse() { check(); work.browse(); } }
3. 应用场景
9.工厂的设计模式
1. 解决的问题
实现了创建者与调用者的分离,即将创建对象的具体过程屏蔽隔离
起来,达到提高灵活性的目的。
2. 具体模式
简单工厂模式:用来生产同一等级结构中的任意产品。(对于增加新的产品, 需要修改已有代码)
工厂方法模式:用来生产同一等级结构中的固定产品。(支持增加任意产品)
抽象工厂模式:用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)
3.核心本质
核心本质:
实例化对象,用工厂方法代替 new 操作。
将择实现类、创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。
七、类的结构之五:内部类(类的第五个成员)
1.定义
Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
2.内部类的分类
成员内部类(静态、非静态) vs 局部内部类(方法内、代码块内、构造器内)
3.成员内部类的理解
一方面,作为外部类的成员:
>调用外部类的结构
>可以被static修饰
>可以被4种不同的权限修饰另一方面,作为一个类:
>类内可以定义属性、方法、构造器
>可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
>可以被abstract修饰
4.成员内部类
4.1如何创建成员内部类的对象?(静态的,非静态的)
//创建静态的Dog内部类的实例(静态的成员内部类)
Person.Dog dog = new Person.Dog();
dog.show();//调用内部类的show()方法
//创建非静态的Bird内部类的实例(非静态的成员内部类)
//Person.Bird bird = new Person.Bird();//错误的
Person p = new Person();
Person.Bird bird = p.new Bird();
bird.sing();//调用内部类的sing()方法
4.2如何在成员内部类中调用外部类的结构?
class Person{ String name = "小明"; public void eat() { System.out.println("吃饭"); } //非静态成员内部类 class Bird{ String name = "杜鹃"; public void dispaly(String name) { System.out.println(name);//方法的形参 System.out.println(this.name);//内部类的属性 System.out.println(Person.this.name);//外部类的属性 //若是内部类与外部类没重名,可直接调用属性、方法 //Person.this.eat(); eat();//省略了Person.this. } } }
5.局部内部类的使用
//开发中很少见 public void method() { //局部内部类 class AA{ } } //开发中常见的内部类使用是有返回值的 //返回一个实现了Comparable接口类的对象 public Comparable getComparaable(){ //创建一个实现了Comparable接口的类:局部内部类 //方式一: // class MyComparable implements Comparable{ // // @Override // public int compareTo(Object o) { // // TODO Auto-generated method stub // return 0; // } // // } // return new MyComparable(); //方式二:创建了一个接口的的匿名实现类的匿名对象 return new Comparable() { @Override public int compareTo(Object o) { // TODO Auto-generated method stub return 0; } }; }
6.注意点
在局部内部类的方法中(比如:show)如果调用局部内部类所声明的方法(比如:method)中的局部变量的话要求此局部变量声明为final的。
jdk 7及之前版本:要求此局部变量显式的声明为final的
jdk 8及之后的版本,可以省略final的声明public void method() { //局部变量 int num = 10;//final int num = 10; class aa{ public void show() { // num = 20; System.out.println(num); } } }
7.总结
成员内部类和局部内部类,在编译以后,都会生成字节码文件
格式:成员内部类:外部类$内部类名.calss
局部内部类:外部类$数字 内部类名.class