类变量和类办法
类变量-提出问题
在main办法中定义一个变量count,当一个小孩退出游戏后count++,最初个count 就记录有多少小孩玩游戏 。
问题剖析:
count是一个独立于对象,很难堪,当前咱们拜访count很麻烦,没有应用到OOP。因而,咱们引出类变量/动态变量。
package com.hspedu.static_;
public class ChildGame {
public static void main(String[] args) {
//定义一个变量 count, 统计有多少小孩退出了游戏
int count = 0;
Child child1 = new Child("白骨精");
child1.join();
//count++;
child1.count++;
Child child2 = new Child("狐狸精");
child2.join();
//count++;
child2.count++;
Child child3 = new Child("老鼠精");
child3.join();
//count++;
child3.count++;
//===========
// 类变量,能够通过类名来拜访
System.out.println("共有" + Child.count + " 小孩退出了游戏...");
// 上面的代码输入什么?
System.out.println("child1.count=" + child1.count);//3
System.out.println("child2.count=" + child2.count);//3
System.out.println("child3.count=" + child3.count);//3
}
}
class Child { //类
private String name;
// 定义一个变量 count ,是一个类变量(动态变量) static 动态!!!
// 该变量最大的特点就是会被 Child 类的所有的对象实例共享!!!
public static int count = 0;
public Child(String name) {
this.name = name;
}
public void join() {
System.out.println(name + " 退出了游戏..");
}
}
类变量内存布局
https://blog.csdn.net/x_iya/article/details/81260154/
https://www.zhihu.com/question/59174759/answer/163207831
有些书说在办法区… jdk 版本有关系,记住两点:
(1) static变量是同一个类所有对象共享
(2) static类变量,在类加载的时候就生成了.动态变量是类加载的时候,就创立了,所以不必创建对象实例也能间接通过 类名.类变量名
拜访。
什么是类变量
类变量也叫动态变量/动态属性,是该类的所有对象共享的变量,任何一个该类的对象去拜访它时,取到的都是雷同的值,同样任何一个该类的对象去批改它时,批改的也是同一个变量。这个从后面的图也可看进去。
如何定义类变量
定义语法:
拜访修饰符static数据类型变量名;[举荐]
static拜访修饰符数据类型变量名;
如何拜访类变量
类名.类变量名
或者对象名.类变量名【动态变量的拜访修饰符的拜访权限和范畴和一般属性是一样的】
举荐应用:类名.类变量名;
类变量应用注意事项
1.什么时候须要用类变量
当咱们须要让某个类的所有对象都共享一个变量时,就能够思考应用类变量(动态变量):比方:定义学生类,统计所有学生共交多少钱。Student (name, staticfee)
2.类变量与实例变量(一般属性)区别
类变量是该类的所有对象共享的,而实例变量是每个对象独享的。
3.加上static称为类变量或动态变量,否则称为实例变量/一般变量/非动态变量
4.类变量能够通过类名.类变量名或者对象名.类变量名来拜访,但java设计者举荐咱们应用类名.类变量名形式拜访。【前提是满足拜访修饰符的拜访权限和范畴】
5.实例变量不能通过类名.类变量名形式拜访。
6.类变量是在类加载时就初始化了,也就是说,即便你没有创建对象,只有类加载了.就能够应用类变量了。
7.类变量的生命周期是随类的加载开始,随着类沦亡而销毁。
类办法根本介绍
类办法也叫静态方法。模式如下:
拜访修饰符 static 数据返回类型 办法名(){}【举荐】
static 拜访修饰符 数据返回类型 办法名(){}
类办法的调用
应用形式:
类名.类办法名或者对象名.类办法名
package com.hspedu.static_;
public class StaticMethod {
public static void main(String[] args) {
//创立2个学生对象,叫学费
Stu tom = new Stu("tom");
//tom.payFee(100);
Stu.payFee(100);//对不对?对
Stu mary = new Stu("mary");
//mary.payFee(200);
Stu.payFee(200);//对
//输入以后收到的总学费
Stu.showFee();//300
//如果咱们心愿不创立实例,也能够调用某个办法(即当做工具来应用)
//这时,把办法做成静态方法时十分适合
System.out.println("9开平方的后果是=" + Math.sqrt(9));
System.out.println(MyTools.calSum(10, 30));
}
}
//开发本人的工具类时,能够将办法做成动态的,不便调用
class MyTools {
//求出两个数的和
public static double calSum(double n1, double n2) {
return n1 + n2;
}
//能够写出很多这样的工具办法...
}
class Stu {
private String name;//一般成员
//定义一个动态变量,来累积学生的学费
private static double fee = 0;
public Stu(String name) {
this.name = name;
}
// 阐明
// 1. 当办法应用了static润饰后,该办法就是静态方法
// 2. 静态方法就能够拜访动态属性/变量
public static void payFee(double fee) {
Stu.fee += fee;//累积到
}
public static void showFee() {
System.out.println("总学费有:" + Stu.fee);
}
}
类办法经典的应用场景
当办法中不波及到任何和对象相干的成员,则能够将办法设计成静态方法, 进步开发效率。
比方:
工具类中的办法utils。Math类、Arrays类、Collections汇合类看下源码能够发现都是static办法。
类办法应用注意事项和细节探讨
- 类办法和一般办法都是随着类的加载而加载,将构造信息存储在办法区∶类办法中无this的参数。一般办法中隐含着this的参数。
- 类办法能够通过类名调用,也能够通过对象名调用。一般办法和对象无关,须要通过对象名调用,比方对象名.办法名(参数),不能通过类名调用。
- 类办法中不容许应用和对象无关的关键字,比方this和super。一般办法(成员办法)能够。
- 类办法(静态方法)中只能拜访动态变量或静态方法。一般成员办法,既能够拜访非动态成员,也能够拜访动态成员!!
package com.hspedu.static_;
public class StaticMethodDetail {
public static void main(String[] args) {
D.hi();//ok
//非静态方法,不能通过类名调用
//D.say();, 谬误,须要先创建对象,再调用
new D().say();//能够
}
}
class D {
private int n1 = 100;
private static int n2 = 200;
public void say() {//非静态方法,一般办法
}
public static void hi() {//静态方法,类办法
//类办法中不容许应用和对象无关的关键字,
//比方this和super。一般办法(成员办法)能够。
//System.out.println(this.n1);
}
//类办法(静态方法)中 只能拜访 动态变量 或静态方法
//口诀:静态方法只能拜访动态成员.
public static void hello() {
System.out.println(n2);
System.out.println(D.n2);
//System.out.println(this.n2);不能应用
hi();//OK
//say();//谬误
}
//一般成员办法,既能够拜访 非动态成员,也能够拜访动态成员
//小结: 非静态方法能够拜访 动态成员和非动态成员
public void ok() {
//非动态成员
System.out.println(n1);
say();
//动态成员
System.out.println(n2);
hello();
}
}
练习:
package com.hspedu.static_;
public class StaticExercise03 {
}
class Person {
private int id;
private static int total = 0;
public static void setTotalPerson(int total){
// this.total = total;//谬误,因为在static办法中,不能够应用this 关键字
Person.total = total;
}
public Person() {//结构器
total++;
id = total;
}
//编写一个办法,输入total的值
public static void m() {
System.out.println("total的值=" + total);
}
}
class TestPerson {
public static void main(String[] args) {
Person.setTotalPerson(3); // 这里没有调用结构器
new Person(); // new了之后调用结构器,count++
Person.m();// 最初 total的值就是4
}
}
留神:
Person.setTotalPerson(3); 调用静态方法 这里还没有调用结构器
new Person(); new了之后才调用结构器,count++
因为结构器是在创建对象时实现对对象的初始化。
了解main 办法语法
深刻了解main 办法
解释main办法的模式: public static void main(String[] args){}
1.main办法时虚拟机调用
2.java虚拟机须要调用类的main()办法,所以该办法的拜访权限必须是public
3.java虚拟机在执行main()办法时不用创建对象,所以该办法必须是static
4.该办法接管String类型的数组参数,该数组中保留执行java命令时传递给所运行的类的参数,案例演示,接管参数.
5.java执行的程序参数1参数2参数。
阐明:在idea如何传递参数?
在Program arguments 中传入参数即可。
特地提醒
在main()办法中,咱们能够间接调用main 办法所在类的静态方法或动态属性。然而,不能间接拜访该类中的非动态成员,必须创立该类的一个实例对象后,能力通过这个对象去拜访类中的非动态成员。
代码块
根本介绍
代码化块又称为初始化块,属于类中的成员[即是类的一部分],相似于办法,将逻辑语句封装在办法体中,通过包围起来。
但和办法不同,没有办法名,没有返回,没有参数,只有办法体,而且不必通过对象或类显式调用,而是加载类时,或创建对象时隐式调用。
根本语法
[修饰符]{
代码
};
阐明留神;
- 修饰符可选,要写的话,也只能写static
- 代码块分为两类,应用static润饰的叫动态代码块,没有static润饰的,叫一般代码块/非动态代码块。
- 逻辑语句能够为任何逻辑语句(输出、输入、办法调用、循环、判断等)
- ;号能够写上,也能够省略。
代码块的益处和案例演示
- 相当于另外一种模式的结构器(对结构器的补充机制),能够做初始化的操作
- 场景:如果多个结构器中都有反复的语句,能够抽取到初始化块中,进步代码的重用性
这样当咱们不论调用哪个结构器,创建对象,都会先调用代码块的内容,代码块调用的程序优先于结构器。
package com.hspedu.codeblock_;
public class CodeBlock01 {
public static void main(String[] args) {
Movie movie = new Movie("你好,李焕英");
System.out.println("===============");
Movie movie2 = new Movie("唐探3", 100, "陈思诚");
}
}
class Movie {
private String name;
private double price;
private String director;
// 3个结构器-》重载
{
System.out.println("电影屏幕关上...");
System.out.println("广告开始...");
System.out.println("电影正是开始...");
};
public Movie(String name) {
System.out.println("Movie(String name) 被调用...");
this.name = name;
}
public Movie(String name, double price) {
this.name = name;
this.price = price;
}
public Movie(String name, double price, String director) {
System.out.println("Movie(String name, double price, String director) 被调用...");
this.name = name;
this.price = price;
this.director = director;
}
}
代码块应用注意事项和细节探讨!!!
- static代码块也叫动态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是一般代码块,每创立一个对象, 就执行一次。
- 类什么时候被加载
- 创建对象实例时(new)
- 创立子类对象实例,父类也会被加载
- 应用类的动态成员时(动态属性,静态方法)
- 一般的代码块,在创建对象实例时,会被隐式的调用。被创立一次,就会调用一次。
如果只是应用类的动态成员时,一般代码块并不会执行。(没有创建对象实例)
- 创立一个对象时,在一个类调用程序是 (重点,难点) ∶
- 调用动态代码块和动态属性初始化 (留神:动态代码块和动态属性初始化调用的优先级一样,如果有多个动态代码块和多个动态变量初始化,则按他们定义的先后顺序调用)
- 调用一般代码块和一般属性的初始化(留神:一般代码块和一般属性初始化调用的优先级一样,如果有多个一般代码块和多个一般属性初始化,则按定义先后顺序调用)
- 调用构造方法
- 结构器的最后面其实隐含了super()和调用一般代码块, 动态相干的代码块,属性初始化,在类加载时,就执行结束,因而是优先于结构器和一般代码块执行的。
- 咱们看一下创立一个子类对象时(继承关系),他们的调用程序如下:
- 父类的动态代码块和动态属性(优先级一样,按定义程序执行)(类加载)
- 子类的动态代码块和动态属性(优先级一样,按定义程序执行)(类加载)
- 父类的一般代码块和一般属性初始化(优先级一样,按定义程序执行)
- 父类的构造方法
- 子类的一般代码块和一般属性初始化(优先级一样,按定义程序执行)
- 子类的构造方法
- 动态代码块(实质上是静态方法)只能间接调用动态成员(动态属性和静态方法),一般代码块(实质上是一般办法)能够调用任意成员。
package com.hspedu.codeblock_;
public class CodeBlockDetail04 {
public static void main(String[] args) {
//老师阐明
//(1) 进行类的加载
//1.1 先加载 父类 A02 1.2 再加载 B02
//(2) 创建对象
//2.1 从子类的结构器开始
//new B02();//对象
new C02();
}
}
class A02 { //父类
private static int n1 = getVal01();
static {
System.out.println("A02的一个动态代码块..");//(2)
}
{
System.out.println("A02的第一个一般代码块..");//(5)
}
pulic int n3 = getVal02();//一般属性的初始化
public static int getVal01() {
System.out.println("getVal01");//(1)
return 10;
}
public int getVal02() {
System.out.println("getVal02");//(6)
return 10;
}
public A02() {//结构器
//暗藏
//super()
//一般代码和一般属性的初始化......
System.out.println("A02的结构器");//(7)
}
}
class C02 {
private int n1 = 100;
private static int n2 = 200;
private void m1() {
}
private static void m2() {
}
static {
//动态代码块,只能调用动态成员
//System.out.println(n1);谬误
System.out.println(n2);//ok
//m1();//谬误
m2();
}
{
//一般代码块,能够应用任意成员
System.out.println(n1);
System.out.println(n2);//ok
m1();
m2();
}
}
class B02 extends A02 { //
private static int n3 = getVal03();
static {
System.out.println("B02的一个动态代码块..");//(4)
}
public int n5 = getVal04();
{
System.out.println("B02的第一个一般代码块..");//(9)
}
public static int getVal03() {
System.out.println("getVal03");//(3)
return 10;
}
public int getVal04() {
System.out.println("getVal04");//(8)
return 10;
}
//肯定要缓缓的去品..
public B02() {//结构器
//暗藏了
//super()
//一般代码块和一般属性的初始化...
System.out.println("B02的结构器");//(10)
// TODO Auto-generated constructor stub
}
}
练习:
package com.hspedu.codeblock_;
public class CodeBlockExercise02 {
}
class Sample
{
Sample(String s)
{
System.out.println(s);
}
Sample()
{
System.out.println("Sample默认构造函数被调用");
}
}
class Test{
Sample sam1=new Sample("sam1成员初始化");//
static Sample sam=new Sample("动态成员sam初始化 ");//
static{
System.out.println("static块执行");//
if(sam==null)System.out.println("sam is null");
}
Test()//结构器
{
System.out.println("Test默认构造函数被调用");//
}
//主办法
public static void main(String str[])
{
Test a=new Test();//无参结构器
}
}
1. 动态成员sam 初始化
2. static 块执行
3. sam1 成员初始化
4. Test 默认构造函数被调用
单例设计模式
什么是设计模式
静态方法和属性的经典应用
设计模式是在大量的实际中总结和理论化之后优选的代码构造、编程格调、以及解决问题的思考形式。设计模式就像是经典的棋谱,不同的棋局,咱们用不同的棋谱,免去咱们本人再思考和摸索。
什么是单例模式
- 所谓类的单例设计模式,就是采取肯定的办法保障在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个获得其对象实例的办法。
- 单例模式有两种形式:1) 饿汉式 2) 懒汉式
饿汉式
步骤如下:
- 结构器私有化 =》避免间接new
- 类的外部创建对象
- 向外裸露一个动态的公共办法。getlnstance
饿汉式:有可能还没有用到这个对象,然而因为类的机制曾经将对象创立好了。在线程还没呈现之前就曾经实例化了,因而饿汉式线程肯定是平安的。
package com.hspedu.single_;
public class SingleTon01 {
public static void main(String[] args) {
// GirlFriend xh = new GirlFriend("小红");
// GirlFriend xb = new GirlFriend("小白");
//通过办法能够获取对象
GirlFriend instance = GirlFriend.getInstance();
System.out.println(instance);
// 都是同一个对象
GirlFriend instance2 = GirlFriend.getInstance();
System.out.println(instance2);
System.out.println(instance == instance2);// T 同一个对象
//System.out.println(GirlFriend.n1);
}
}
// 有一个类, GirlFriend
// 只能有一个女朋友
class GirlFriend {
private String name;
// public static int n1 = 100;
// 为了可能在静态方法中,返回 gf对象,须要将其润饰为static
// 對象,通常是分量級的對象, 餓漢式可能造成創建了對象,然而沒有应用.
// 只有类加载了,就肯定创立了gf对象
private static GirlFriend gf = new GirlFriend("小红红");
// 如何保障咱们只能创立一个 GirlFriend 对象
// 步骤[单例模式-饿汉式]
// 1. 将结构器私有化
// 2. 在类的外部间接创建对象(该对象是static)
// 3. 提供一个公共的static办法,返回 gf 对象
private GirlFriend(String name) {
System.out.println("構造器被調用.");
this.name = name;
}
// 用static的目标就是在不创建对象的前提下间接调用
public static GirlFriend getInstance() {
return gf;
}
@Override
public String toString() {
return "GirlFriend{" +
"name='" + name + '\'' +
'}';
}
}
懒汉式
懶漢式,只有當用戶应用getInstance時,才返回cat對象, 後面再次調用時,會返回上次創建的cat對象。
懒汉式可能会存在线程平安的问题。
package com.hspedu.single_;
/**
* 演示懶漢式的單例模式
*/
public class SingleTon02 {
public static void main(String[] args) {
//new Cat("大黃");
//System.out.println(Cat.n1);
Cat instance = Cat.getInstance();
System.out.println(instance);
//再次調用getInstance
Cat instance2 = Cat.getInstance();
System.out.println(instance2);
System.out.println(instance == instance2);//T
}
}
//心愿在程序運行過程中,只能創建一個Cat對象
//应用單例模式
class Cat {
private String name;
public static int n1 = 999;
private static Cat cat ; //默認是null
//步驟
//1.依然構造器私有化
//2.定義一個static靜態屬性對象
//3.提供一個public的static办法,能够返回一個Cat對象
//4.懶漢式,只有當用戶应用getInstance時,才返回cat對象, 後面再次調用時,會返回上次創建的cat對象
// 從而保證了單例
private Cat(String name) {
System.out.println("構造器調用...");
this.name = name;
}
public static Cat getInstance() {
if(cat == null) {//如果還沒有創建cat對象
cat = new Cat("小可愛");
}
return cat;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}
比拟
- 二者最次要的区别在于创建对象的机会不同:饿汉式是在类加载就创立了对象实例,而懒汉式是在应用时才创立。
- 饿汉式不存在线程平安问题,懒汉式存在线程平安问题。(前面学习线程后,会欠缺一把)。
- 饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有应用,那么饿汉式创立的对象就节约了,懒汉式是应用时才创立,就不存在这个问题。
- 在咱们javaSE规范类中,java.lang.Runtime就是经典的单例模式.
final 关键字
根本介绍
final中文意思:最初的,最终的.
final能够润饰类、属性、办法和局部变量
在某些状况下,程序员可能有以下需要,就会应用到final:
- 当不心愿类被继承时,能够用final润饰.
- 当不心愿父类的某个办法被子类笼罩/重写(override)时,能够用final关键字润饰。【案例演示:拜访修饰符final返回类型办法名】
- 当不心愿类的的某个属性的值被批改,能够用final润饰.(例如: public final double TAX RATE=0.08)
- 当不心愿某个局部变量被批改,能够应用final润饰(例如: final double TAX RATE=0.08)
final 应用注意事项和细节探讨
- final润饰的属性又叫常量,个别用 XX_XX_XX (大写)来命名
- final润饰的属性在定义时,必须赋初值,并且当前不能再批改,赋值能够在如下地位之一:
定义时:如public final double TAX_RATE=0.08;
在结构器中
在代码块中
class AA {
/*
1. 定义时:如public final double TAX_RATE=0.08;
2. 在结构器中
3. 在代码块中
*/
public final double TAX_RATE = 0.08;//1.定义时赋值
public final double TAX_RATE2 ;
public final double TAX_RATE3 ;
public AA() {//结构器中赋值
TAX_RATE2 = 1.1;
}
{//在代码块赋值
TAX_RATE3 = 8.8;
}
}
- 如果final润饰的属性是动态的,则初始化的地位只能是
①定义时
②在动态代码块(不能在结构器中赋值。因为结构器是在对象创立的时候才会进行赋值)
- final类不能继承,然而能够实例化对象。(实例化没问题)
- 如果类不是final类,然而含有final办法,则该办法尽管不能重写,然而能够被继承。(子类用是没问题的,尽管不能重写)
- 一般来说,如果一个类曾经是final类了,就没有必要再将办法润饰成final办法。(因为类既然不能被继承,也就相应无奈被重写)。
- final不能润饰构造方法(即结构器)。
- final和static 往往搭配应用,效率更高,因为不会导致类加载,底层编译器做了优化解决。
- 包装类(Integer,Double,Float,Boolean等都是final),String也是final类。
抽象类
引出
当父类的某些办法,须要申明,然而又不确定如何实现时,能够将其申明为形象办法,那么这个类就是抽象类。
所谓形象办法就是没有实现的办法,所谓没有实现就是指,没有办法体。
当一个类中存在形象办法时,须要将该类申明为abstract 类,一般来说,抽象类会被继承,由其子类来实现形象办法。
abstract class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public abstract void eat() ;
}
抽象类的介绍
1)用abstract关键字来润饰一个类时,这个类就叫抽象类拜访修饰符
2)用abstract关键字来润饰一个办法时,这个办法就是形象办法
拜访修饰符 abstract 返回类型 办法名(参数列表);//没有办法体
3)抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类。
4)抽象类是考官比拟爱问的知识点,在框架和设计模式应用较多。
抽象类应用的注意事项和细节探讨
1)抽象类不能被实例化
2)抽象类不肯定要蕴含abstract办法。也就是说, 抽象类能够没有abstract办法。
3)一旦类蕴含了abstract办法,则这个类必须申明为abstract。
4)abstract只能润饰类和办法,不能润饰属性和其它的。
5)抽象类能够有任意成员【抽象类实质还是类】,比方: 非形象办法、结构器、动态属性等等。
6)形象办法不能有主体,即不能实现。
7)如果一个类继承了抽象类,则它必须实现抽象类的所有形象办法,除非它本人也申明为abstract类。
8)形象办法不能应用private、final和 static来润饰,因为这些关键字都是和重写相违反的。
抽象类最佳实际-模板设计模式
根本介绍
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的根底上进行扩大、革新,但子类总体上会保留抽象类的行为形式。
模板设计模式能解决的问题
1)当性能外部一部分实现是确定,一部分实现是不确定的。这时能够把不确定的局部裸露进来,让子类去实现。
2)编写一个形象父类,父类提供了多个子类的通用办法,并把一个或多个办法留给其子类实现,就是一种模板模式.
最佳实际
需要:
有多个类,实现不同的工作job
要求统计失去各自实现工作的工夫
package com.hspedu.abstract_;
abstract public class Template { //抽象类-模板设计模式
public abstract void job();//形象办法
public void calculateTime() {//实现办法,调用job办法
//失去开始的工夫
long start = System.currentTimeMillis();
job(); //动静绑定机制
//得的完结的工夫
long end = System.currentTimeMillis();
System.out.println("工作执行工夫 " + (end - start));
}
}
以上就是把不确定的局部裸露进来,让子类去实现。
接口
根本介绍
接口就是给出一些没有实现的办法,封装到一起,到某个类要应用的时候,在依据具体情况把这些办法写进去。语法:
interface 接口名{
//属性
//形象办法(接口中能够省略abstract关键字)(在jdk8后还能够有静态方法和默认办法)
}
class 类名 implements 接口 {
// 本人属性;
// 本人办法;
// 必须实现的接口的形象办法
}
小结:
接口是更加形象的类。抽象类里的办法能够有办法体,接口里的所有办法都没有办法体(jdk7.0)。接口体现了程序设计的多态和高内聚低偶合的设计思维。
特地阐明:Jdk8.0后接口类能够有静态方法(static),默认办法(default),也就是说接口中能够有办法的具体实现入。
深刻探讨
说当初有一个项目经理(段玉),治理三个程序员,性能开发一个软件.为了管制和管理软件,项目经理能够定义一些接口,而后由程序员具体实现。
通过接口,不仅能够对立办法名,同时在调用时只须要依据接口辨认即可。
package com.hspedu.interface_;
public interface DBInterface { //项目经理
public void connect();//连贯办法
public void close();//敞开连贯
}
package com.hspedu.interface_;
//A程序
public class MysqlDB implements DBInterface {
@Override
public void connect() {
System.out.println("连贯mysql");
}
@Override
public void close() {
System.out.println("敞开mysql");
}
}
package com.hspedu.interface_;
//B程序员连贯Oracle
public class OracleDB implements DBInterface{
@Override
public void connect() {
System.out.println("连贯oracle");
}
@Override
public void close() {
System.out.println("敞开oracle");
}
}
package com.hspedu.interface_;
public class Interface03 {
public static void main(String[] args) {
MysqlDB mysqlDB = new MysqlDB();
t(mysqlDB);
OracleDB oracleDB = new OracleDB();
t(oracleDB);
}
public static void t(DBInterface db) {
db.connect();
db.close();
}
}
注意事项和细节
- 接口不能被实例化(new)
- 接口中所有的办法是public办法,接口中形象办法,能够不必abstract修
饰。void aaa(); 实际上是abstract void aa();(同理,不写public也是默认public办法,因而实现时该办法不写public会报错。)
- 一个一般类实现接口,就必须将该接口的所有办法都实现。
- 抽象类实现接口,能够不必实现接口的办法。
- 一个类同时能够实现多个接口。
class Timer implements IA, IB{ }
- 接口中的属性,只能是final的,而且是 public static final修饰符。比方:int a=1;实际上是public static final int a=1; (必须初始化)
- 接口中属性的拜访模式:接口名.属性名
- 接口不能继承其它的类,然而能够继承多个别的接口。(接口无奈实现接口)
interface A extends B,C{}
- 接口的修饰符只能是public和默认,这点和类的修饰符是一样的。
实现接口VS继承类
当子类继承了父类,就主动的领有父类的性能,如果子类须要扩大性能,能够通过实现接口的形式扩大。能够了解 实现接口 是对 java 单继承机制的一种补充。
- 接口和继承解决的问题不同
继承的价值次要在于:解决代码的复用性和可维护性。
- 接口的价值次要在于:设计,设计好各种标准(办法),让其它类去实现这些办法。即更加的灵便
接口比继承更加灵便:继承是满足is – a的关系,而接口只需满足 like – a的关系。
接口在肯定水平上实现代码解耦[即:接口规范性+动静绑定机制]
接口的多态个性
- 多态参数
在后面的Usb接口案例,UsbInterface usb,既能够接管手机对象,又能够接管相机对象,就体现了接口多态(接口援用能够指向实现了接口的类的对象)。
package com.hspedu.interface_;
public class InterfacePolyParameter {
public static void main(String[] args) {
//接口的多态体现
//接口类型的变量 if01 能够指向 实现了IF接口类的对象实例
IF if01 = new Monster();
if01 = new Car();
// 继承体现的多态
// 父类类型的变量 a 能够指向 继承AAA的子类的对象实例
AAA a = new BBB();
a = new CCC();
}
}
interface IF {}
class Monster implements IF{}
class Car implements IF{}
class AAA {
}
class BBB extends AAA {}
class CCC extends AAA {}
2. 多态数组
演示一个案例:给**Usb数组中,寄存 Phone 和相机对象**,Phone类还有一个特有的办法call(),请遍历Usb数组,如果是Phone对象,除了调用Usb接口定义的办法外,还须要调用Phone特有办法call。
```java
package com.hspedu.interface_;
public class InterfacePolyArr {
public static void main(String[] args) {
//多态数组 -> 接口类型数组
Usb[] usbs = new Usb[2];
usbs[0] = new Phone_();
usbs[1] = new Camera_();
/*
给Usb数组中,寄存 Phone 和 相机对象,Phone类还有一个特有的办法call(),
请遍历Usb数组,如果是Phone对象,除了调用Usb 接口定义的办法外,
还须要调用Phone 特有办法 call
*/
for(int i = 0; i < usbs.length; i++) {
usbs[i].work();//动静绑定..
//和后面一样,咱们依然须要进行类型的向下转型
if(usbs[i] instanceof Phone_) {//判断他的运行类型是 Phone_
((Phone_) usbs[i]).call();
}
}
}
}
interface Usb{
void work();
}
class Phone_ implements Usb {
public void call() {
System.out.println("手机能够打电话...");
}
@Override
public void work() {
System.out.println("手机工作中...");
}
}
class Camera_ implements Usb {
@Override
public void work() {
System.out.println("相机工作中...");
}
}
- 接口存在多态传递景象
package com.hspedu.interface_;
/**
* 演示多态传递景象
*/
public class InterfacePolyPass {
public static void main(String[] args) {
//接口类型的变量能够指向,实现了该接口的类的对象实例
IG ig = new Teacher();
//如果IG 继承了 IH 接口,而Teacher 类实现了 IG接口
//那么,实际上就相当于 Teacher 类也实现了 IH接口.
//这就是所谓的 接口多态传递景象.
IH ih = new Teacher();
}
}
interface IH {
void hi();
}
interface IG extends IH{ }
class Teacher implements IG {
@Override
public void hi() {
}
}
外部类
如果定义类在部分地位(办法中/代码块) (1) 部分外部类 (2) 匿名外部类
定义在成员地位 (1) 成员外部类 (2) 动态外部类
根本介绍
一个类的外部又残缺的嵌套了另一个类构造。被嵌套的类称为外部类(inner class),嵌套其余类的类称为外部类(outer class)。
是咱们类的第五大成员(类的五大成员:属性、办法、结构器、代码块、外部类),外部类最大的特点就是能够间接拜访公有属性,并且能够体现类与类之间的蕴含关系,留神:外部类是学习的难点,同时也是重点,前面看底层源码时,有大量的外部类。
根本语法
class Outer{ // 外部类
class Inner{
// 外部类
}
}
class Other{// 内部其余类
}
外部类的分类
定义在外部类部分地位上( 比方办法内 ):
- 部分外部类 ( 有类名 )
- 匿名外部类 ( 没有类名,重点!!!!!!!! )
定义在外部类的成员地位上:
- 成员外部类 ( 没用 static 润饰 )
- 动态外部类 ( 应用 static 润饰 )
部分外部类的应用
阐明:部分外部类是定义在外部类的部分地位,比方办法中,并且有类名。
1.能够间接拜访外部类的所有成员,蕴含公有的。
2.不能增加拜访修饰符,因为它的位置就是一个局部变量。局部变量是不能应用修饰符的。然而能够应用final润饰,因为局部变量也能够应用final。
3.作用域:仅仅在定义它的办法或代码块中。
4.部分外部类拜访外部类的成员[拜访形式:间接拜访]
5.外部类拜访部分外部类的成员
拜访形式: 创建对象,再拜访 (留神:必须在作用域内)
小结:
(1)部分外部类定义在办法中/代码块
(2)作用域在办法体或者代码块中
(3)实质依然是一个类
6.内部其余类不能拜访部分外部类(因为部分外部类位置是一个局部变量)。
7.如果外部类和部分外部类的成员重名时,默认遵循就近准则,如果想拜访外部类的成员,则能够应用(外部类名.this.成员)去拜访。
这里 外部类名.this
实质上就是外部类的对象,即哪个对象调用了n2,那么 外部类名.this
就指向哪个对象。
System.out.printin(""外部类的n2=”+外部类名.this.n2);
package com.hspedu.innerclass;
/**
* 演示部分外部类的应用
*/
public class LocalInnerClass {//
public static void main(String[] args) {
//演示一遍
Outer02 outer02 = new Outer02();
outer02.m1();
System.out.println("outer02的hashcode=" + outer02);
}
}
class Outer02 {//外部类
private int n1 = 100;
private void m2() {
System.out.println("Outer02 m2()");
}//公有办法
public void m1() {//办法
//1.部分外部类是定义在外部类的部分地位,通常在办法
//3.不能增加拜访修饰符,然而能够应用final 润饰
//4.作用域 : 仅仅在定义它的办法或代码块中
final class Inner02 {//部分外部类(实质依然是一个类)
//2.能够间接拜访外部类的所有成员,蕴含公有的
private int n1 = 800;
public void f1() {
//5. 部分外部类能够间接拜访外部类的成员,比方上面 外部类n1 和 m2()
//7. 如果外部类和部分外部类的成员重名时,默认遵循就近准则,如果想拜访外部类的成员,
// 应用 外部类名.this.成员)去拜访
// Outer02.this 实质就是外部类的对象, 即哪个对象调用了m1, Outer02.this就是哪个对象
System.out.println("n1=" + n1 + " 外部类的n1=" + Outer02.this.n1);
System.out.println("Outer02.this hashcode=" + Outer02.this);
m2();
}
}
//6. 外部类在办法中,能够创立Inner02对象,而后调用办法即可
Inner02 inner02 = new Inner02();
inner02.f1();
}
}
匿名外部类的应用!!!!!
(1)实质是类 (2) 外部类 (3) 该类没有名字 (4) 同时还是一个对象
阐明: 匿名外部类是定义在外部类的部分地位, 比方办法中, 并且没有类名
1.匿名外部类的根本语法
new 类或接口 (参数列表){
类体
);
package com.hspedu.innerclass;
/**
* 演示匿名外部类的应用
*/
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04 { //外部类
private int n1 = 10;//属性
public void method() {//办法
//基于!!!接口!!!的匿名外部类
//解读
//1.需要:想应用IA接口,并创建对象
//2.传统形式,是写一个类,实现该接口,并创建对象
//3.需要是 Tiger/Dog 类只是应用一次,前面再不应用
//4. 能够应用匿名外部类来简化开发
//5. tiger的编译类型 ? IA
//6. tiger的运行类型 ? 就是匿名外部类 Outer04$1
/*
咱们看底层 会调配 类名 Outer04$1
class Outer04$1 implements IA {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
}
*/
//7. jdk底层在创立匿名外部类 Outer04$1,立刻马上就创立了 Outer04$1实例,并且把地址
// 返回给 tiger
//8. 匿名外部类应用一次,就不能再应用, 然而tiger这个对象就没有限度了。
IA tiger = new IA() {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
};
System.out.println("tiger的运行类型=" + tiger.getClass());
tiger.cry();
tiger.cry();
tiger.cry();
// IA tiger = new Tiger();
// tiger.cry();
// 演示基于!!!类!!!的匿名外部类
//剖析
//1. father 编译类型 Father
//2. father 运行类型 Outer04$2
//3. 底层会创立匿名外部类
/*
具体的实现代码与正文中的代码近似等价
class Outer04$2 extends Father{
@Override
public void test() {
System.out.println("匿名外部类重写了test办法");
}
}
*/
//4. 同时也间接返回了 匿名外部类 Outer04$2的对象
//5. 留神("jack") 参数列表会传递给 Father 结构器
Father father = new Father("jack"){
@Override
public void test() {
System.out.println("匿名外部类重写了test办法");
}
};
System.out.println("father对象的运行类型=" + father.getClass());//Outer04$2
father.test();
//基于!!!抽象类!!!的匿名外部类
Animal animal = new Animal(){
@Override
void eat() {
System.out.println("小狗吃骨头...");
}
};
animal.eat();
}
}
interface IA {//接口
public void cry();
}
//class Tiger implements IA {
//
// @Override
// public void cry() {
// System.out.println("老虎叫唤...");
// }
//}
//class Dog implements IA{
// @Override
// public void cry() {
// System.out.println("小狗汪汪...");
// }
//}
class Father { //类
public Father(String name) { //结构器
System.out.println("接管到name=" + name);
}
public void test() { //办法
}
}
abstract class Animal { //抽象类
abstract void eat();
}
2.匿名外部类的语法比拟奇异,因为匿名外部类既是一个类的定义.同时它自身也是一个对象,因而从语法上看,它既有定义类的特色,也有创建对象的特色,对后面代码剖析能够看出这个特点,因而能够调用匿名外部类办法。
3.能够间接拜访外部类的所有成员,蕴含公有的。
4、不能增加拜访修饰符,因为它的位置就是一个局部变量。
5.作用域:仅仅在定义它的办法或代码块中。
6.匿名外部类—拜访—->外部类成员[拜访形式:间接拜访]
7.内部其余类—不能拜访—–>匿名外部类(因为匿名外部类位置是一个局部变量)
8.如果外部类和匿名外部类的成员重名时,匿名外部类拜访的话,默认遵循就近准则,如果想拜访外部类的成员,则能够应用(外部类名.this.成员)去拜访
package com.hspedu.innerclass;
public class AnonymousInnerClassDetail {
public static void main(String[] args) {
Outer05 outer05 = new Outer05();
outer05.f1();
//内部其余类---不能拜访----->匿名外部类
System.out.println("main outer05 hashcode=" + outer05);
}
}
class Outer05 {
private int n1 = 99;
public void f1() {
//创立一个基于类的匿名外部类
//不能增加拜访修饰符,因为它的位置就是一个局部变量
//作用域 : 仅仅在定义它的办法或代码块中
Person p = new Person(){
private int n1 = 88;
@Override
public void hi() {
// 能够间接拜访外部类的所有成员,蕴含公有的
// 如果外部类和匿名外部类的成员重名时,匿名外部类拜访的话,
// 默认遵循就近准则,如果想拜访外部类的成员,则能够应用 (外部类名.this.成员)去拜访
System.out.println("匿名外部类重写了 hi办法 n1=" + n1 +
" 内部内的n1=" + Outer05.this.n1 );
// Outer05.this 就是调用 f1的 对象
System.out.println("Outer05.this hashcode=" + Outer05.this);
}
};
p.hi();//动静绑定, 运行类型是 Outer05$1
//也能够间接调用, 匿名外部类自身也是返回对象
// class 匿名外部类 extends Person {}
// new Person(){
// @Override
// public void hi() {
// System.out.println("匿名外部类重写了 hi办法,哈哈...");
// }
// @Override
// public void ok(String str) {
// super.ok(str);
// }
// }.ok("jack");
}
}
class Person {//类
public void hi() {
System.out.println("Person hi()");
}
public void ok(String str) {
System.out.println("Person ok() " + str);
}
}
//抽象类/接口...
匿名外部类的最佳实际
当做实参间接传递,简洁高效。
package com.hspedu.innerclass;
import com.hspedu.abstract_.AA;
public class InnerClassExercise01 {
public static void main(String[] args) {
//当做实参间接传递,简洁高效
f1(new IL() {
@Override
public void show() {
System.out.println("这是一副名画~~...");
}
});
//传统办法
f1(new Picture());
}
//静态方法,形参是接口类型
public static void f1(IL il) {
il.show();
}
}
//接口
interface IL {
void show();
}
//类->实现IL => 编程畛域 (硬编码)
class Picture implements IL {
@Override
public void show() {
System.out.println("这是一副名画XX...");
}
}
有一个铃声接口Bell,外面有个ring办法。有一个手机类Cellphone,具备闹钟性能alarmclock,参数是Bell类型。测试手机类的闹钟性能,通过匿名外部类(对象)作为参数,打印:懒猪起床了。再传入另一个匿名外部类(对象),打印:小伙伴上课了
package com.hspedu.innerclass;
public class InnerClassExercise02 {
public static void main(String[] args) {
/*
1.有一个铃声接口Bell,外面有个ring办法。(右图)
2.有一个手机类Cellphone,具备闹钟性能alarmClock,参数是Bell类型(右图)
3.测试手机类的闹钟性能,通过匿名外部类(对象)作为参数,打印:懒猪起床了
4.再传入另一个匿名外部类(对象),打印:小伙伴上课了
*/
CellPhone cellPhone = new CellPhone();
//老韩解读
//1. 传递的是实现了 Bell接口的匿名外部类 InnerClassExercise02$1
//2. 重写了 ring
//3. Bell bell = new Bell() {
// @Override
// public void ring() {
// System.out.println("懒猪起床了");
// }
// }
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("懒猪起床了");
}
});
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("小伙伴上课了");
}
});
}
}
interface Bell{ //接口
void ring();//办法
}
class CellPhone{//类
public void alarmClock(Bell bell){//形参是Bell接口类型
System.out.println(bell.getClass());
bell.ring();//动静绑定
}
}
成员外部类的应用
阐明: 成员外部类是定义在外部类的成员地位,并且没有static润饰。
1.能够间接拜访外部类的所有成员,蕴含公有的。
2.能够增加任意拜访修饰符(public、protected、默认、private), 因为它的地
位就是一个成员。
3.作用域和外部类的其余成员一样,为整个类体比方后面案例,在外部类的成员办法中创立成员外部类对象,再调用办法。
4.成员外部类—拜访—->外部类成员(比方:属性) 拜访形式:间接拜访
5.外部类—拜访——>成员外部类(阐明) 拜访形式:创建对象,再拜访
6.内部其余类—拜访—->成员外部类
7.如果外部类和外部类的成员重名时,外部类拜访的话,默认遵循就近准则,如果想拜访外部类的成员,则能够应用(外部类名.this.成员)去拜访
package com.hspedu.innerclass;
public class MemberInnerClass01 {
public static void main(String[] args) {
Outer08 outer08 = new Outer08();
outer08.t1();
//内部其余类,应用成员外部类的三种形式
// 第一种形式
// outer08.new Inner08(); 相当于把 new Inner08()当做是outer08成员
// 这就是一个语法,不要特地的纠结.
Outer08.Inner08 inner08 = outer08.new Inner08();
inner08.say();
// 第二形式 在外部类中,编写一个办法,能够返回 Inner08对象
Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
inner08Instance.say();
}
}
class Outer08 { //外部类
private int n1 = 10;
public String name = "张三";
private void hi() {
System.out.println("hi()办法...");
}
//1.留神: 成员外部类,是定义在内部内的成员地位上
//2.能够增加任意拜访修饰符(public、protected 、默认、private),因为它的位置就是一个成员
public class Inner08 {//成员外部类
private double sal = 99.8;
private int n1 = 66;
public void say() {
//能够间接拜访外部类的所有成员,蕴含公有的
//如果成员外部类的成员和外部类的成员重名,会恪守就近准则.
//,能够通过 外部类名.this.属性 来拜访外部类的成员
System.out.println("n1 = " + n1 + " name = " + name + " 外部类的n1=" + Outer08.this.n1);
hi();
}
}
//办法,返回一个Inner08实例
public Inner08 getInner08Instance(){
return new Inner08();
}
//写办法
public void t1() {
//应用成员外部类
//创立成员外部类的对象,而后应用相干的办法
Inner08 inner08 = new Inner08();
inner08.say();
System.out.println(inner08.sal);
}
}
动态外部类的应用
阐明:动态外部类是定义在外部类的成员地位, 并且有static润饰
1.能够间接拜访外部类的所有动态成员,蕴含公有的,但不能间接拜访非动态成员。
2.能够增加任意拜访修饰符(public. protected、默认、private),因为它的位置就是一个成员。
3.作用域:同其余的成员,为整个类体。
4.动态外部类—拜访—->外部类(比方:动态属性)[拜访形式:间接拜访所有动态成员]。
5.外部类—拜访——>动态外部类 拜访形式:创建对象,再拜访。
6.内部其余类—拜访—–>动态外部类。
7.如果外部类和动态外部类的成员重名时,动态外部类拜访的时,默认遵循就近准则,如果想拜访外部类的成员,则能够应用(外部类名.成员)去访向。
package com.hspedu.innerclass;
public class StaticInnerClass01 {
public static void main(String[] args) {
Outer10 outer10 = new Outer10();
outer10.m1();
//内部其余类 应用动态外部类
//形式1
//因为动态外部类,是能够通过类名间接拜访(前提是满足拜访权限)
Outer10.Inner10 inner10 = new Outer10.Inner10();
inner10.say();
//形式2
//编写一个办法,能够返回动态外部类的对象实例.
Outer10.Inner10 inner101 = outer10.getInner10();
System.out.println("============");
inner101.say();
Outer10.Inner10 inner10_ = Outer10.getInner10_();
System.out.println("************");
inner10_.say();
}
}
class Outer10 { //外部类
private int n1 = 10;
private static String name = "张三";
private static void cry() {}
//Inner10就是动态外部类
//1. 放在外部类的成员地位
//2. 应用static 润饰
//3. 能够间接拜访外部类的所有动态成员,蕴含公有的,但不能间接拜访非动态成员
//4. 能够增加任意拜访修饰符(public、protected 、默认、private),因为它的位置就是一个成员
//5. 作用域 :同其余的成员,为整个类体
static class Inner10 {
private static String name = "Timerring";
public void say() {
//如果外部类和动态外部类的成员重名时,动态外部类拜访的时,
//默认遵循就近准则,如果想拜访外部类的成员,则能够应用 (外部类名.成员)
System.out.println(name + " 外部类name= " + Outer10.name);
cry();
}
}
public void m1() { //外部类---拜访------>动态外部类 拜访形式:创建对象,再拜访
Inner10 inner10 = new Inner10();
inner10.say();
}
public Inner10 getInner10() {
return new Inner10();
}
public static Inner10 getInner10_() {
return new Inner10();
}
}
课堂测试题
判断输入:
package com.hspedu.innerclass;
public class InnerClassExercise {
public static void main(String[] args) {
}
}
class Test {//外部类
public Test() {//结构器
Inner s1 = new Inner();
s1.a = 10;
Inner s2 = new Inner();
System.out.println(s2.a);
}
class Inner { //外部类,成员外部类
public int a = 5;
}
public static void main(String[] args) {
Test t = new Test();
Inner r = t.new Inner();//5
System.out.println(r.a);//5
}
}
文章和代码曾经归档至【Github仓库:https://github.com/timerring/java-tutorial 】或者公众号【AIShareLab】回复 java 也可获取。
发表回复