静态变量与实例变量
含义:static
表示为静态的,静止的
static 可以用来修饰类中的属性、方法、代码块、内部类
static 的作用,我们将用 static 修饰的属性称为 静态属性,或者静态变量
按是否使用使用 static 修饰,分为 静态属性 VS 非静态属性(实例变量)
实例变量:我们创建了类的多个对象,每个对象都有一套独立的非静态属性。当修改其中一个对象的非静态属性时,其他对象中的属性值不会受到影响。
静态属性:我们创建了类的多个对象,多个对象会 **共享 ** 一个静态属性,当通过某个对象去修改这个静态属性时,其他对象都会受到影响,即其他对象再去调用这个属性时结果都是修改之后的值。
static 修饰符的其他说明
静态属性随着类加载而加载,可以通过 类.类变量 来调用静态属性
静态变量加载要早于类
由于类只会被加载一次,所以静态属性在内存中也只会保存一份,存在方法区的静态域中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class StaticTest { public static void main (String[] args) { Student s1 = new Student("李四" ,1001 ); Student s2 = new Student("张三" ,1002 ); s1.schoolName = "县第一高级中学" ; System.out.println(s2.schoolName); s2.schoolName = "县一中" ; System.out.println(s1.schoolName); s1.name = "张三丰" ; System.out.println(s2.name); } } class Student { String name; int id; static String schoolName; public Student (String name, int id) { this .name = name; this .id = id; } }
可以直接使用 类.静态属性
1 2 3 4 5 6 7 8 9 10 11 12 public class StaticTest2 { public static void main (String[] args) { Stu.schoolName = "市立一中" ; Stu s = new Stu(); System.out.println(s.schoolName); } } class Stu { static String schoolName; }
static修饰方法 static 也可以修饰方法
静态方法中可以调用静态属性,静态方法。不能调用非静态的属性和方法
非静态方法中既可以调用非静态属性和方法,也可以调用静态属性和方法,当使用静态属性和方法时,前面默认使用的是 类名.属性
, 而不是 this.属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class StaticMethos03 { public static void main (String[] args) { Status.schoolName = "北京大学" ; Status s = new Status(); s.name = "蔡元培" ; s.show(); } } class Status { String name; static String schoolName; public void show () { showName(); System.out.println(schoolName + "的第一任校长是" + name); } public static void showName () { System.out.println(schoolName); show2(); } public static void show2 () { System.out.println(schoolName); } }
如何确定使用static
属性可以被多个对象共享的,不会随着对象不同而改变的
操作静态属性的方法通常定义为静态的
工具类中的方法,通常定义为静态的,比如 Math,Arrays
static 使用练习 编写一个类实现银行账户的概念,属性包含账号、余额、密码、利率、最小存款余额。
分析哪些属性可以当做静态属性,哪些方法可以设置为静态方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 public class AccountDemo02 { public static void main (String[] args) { Account a1 = new Account(); Account a2 = new Account(2000 ,"qwerty" ); Account.setInterest(0.0123 ); Account.setMinBalance(1000 ); System.out.println("a1的账户信息:" + a1.printInfo()); System.out.println("a2的账户信息:" + a2.printInfo()); } } class Account { private int id; private double balance; private String pwd; private static int initID = 1001 ; private static double interest; private static double minBalance; public Account () { id = initID++; } public Account (double balance,String pwd) { this (); this .balance = balance; this .pwd = pwd; } public String getPwd () { return pwd; } public void setPwd (String pwd) { this .pwd = pwd; } public static double getInterest () { return interest; } public static void setInterest (double interest) { Account.interest = interest; } public static double getMinBalance () { return minBalance; } public static void setMinBalance (double minBalance) { Account.minBalance = minBalance; } public int getId () { return id; } public double getBalance () { return balance; } public String printInfo () { return "账号为:" + this .id + ",余额为:" + this .balance + ",存款利率为" + getInterest() + ",最小存款余额是" + getMinBalance(); } }
单例模式 单例模式表示某个类只能存在一个对象实例
单例模式的饿汉式实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class SingletonTest01 { @Test public void SingletonTest () { Bank b = Bank.getInstance(); Bank b2 = Bank.getInstance(); System.out.println(b == b2); } } class Bank { private Bank () { } private static Bank instance = new Bank(); public static Bank getInstance () { return instance; } }
单例模式的懒汉式实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class SingletonTest02 { @Test public void SingletonTest () { Order o = Order.getInstance(); Order o1 = Order.getInstance(); System.out.println(o == o1); } } class Order { private Order () { } private static Order instance = null ; public static Order getInstance () { if (instance == null ) { instance = new Order(); } return instance; } }
区分饿汉式和懒汉式
饿汉式
懒汉式
坏处:目前上面的写法线程是不安全的
好处:延迟对象的加载
类中代码块结构的使用
代码块的作用:用来初始化类、对象
代码块如果有修饰的话,只能使用 static
用 static
修饰的代码块称为静态代码块 ,不用 static
修饰的称为非静态代码块
静态代码块
内部可以有输出语句
会随着的类的加载而执行,并且只会执行一次
作用:初始化类的信息
如果一个类中定义了多个静态代码块,则按照先后顺序依次执行
静态代码块执行的顺序优先于非静态代码块
静态代码块内部只能调用静态属性和静态方法
非静态代码块
内部可以有输出语句
随着对象的创建而执行
每创建一个对象,就执行一次非静态代码块
作用:可以在创建对象时,对对象的属性进行初始化
如果一个类中定义了多个非静态代码块,则按照先后顺序依次执行
非静态代码块中可以调用静态的属性和方法,也可以调用非静态属性和方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public class BlackCode01 { public static void main (String[] args) { Wallet w1 = new Wallet(); Wallet w2 = new Wallet(); } } class Wallet { double balance; String name; static String from; public Wallet () { System.out.println("空参构造器" ); } static { System.out.println("静态代码块" ); from = "爱马仕" ; print(); } { System.out.println("非静态代码块" ); name = "李冰冰" ; from = "香奈儿" ; show(); print(); } public void show () { System.out.println("show方法" ); } public static void print () { System.out.println("静态打印方法" ); } }
代码块执行顺序练习 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Son { static { System.out.println("111" ); } { System.out.println("222" ); } public Son () { System.out.println("333" ); } } public class BlackCodeTest03 extends Son { static { System.out.println("444" ); } { System.out.println("555" ); } public BlackCodeTest03 () { System.out.println("666" ); } public static void main (String[] args) { new BlackCodeTest03(); } }
属性赋值的先后顺序 ①属性的默认值 –> ②显示的初始化赋值 –> ③代码块中赋值 –> ④构造器中赋值 –> ⑤使用对象调用方法赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class SetValueTest02 { public static void main (String[] args) { Order o = new Order(); System.out.println(o.id); o.setid(4 ); System.out.println(o.id); } } class Order { int id = 1 ; { id = 2 ; } public Order () { id = 3 ; } public void setid (int id) { this .id = id; } }
final 修饰方法和类 final 关键字可以修饰类、方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Person { public final void show () { } } final class Student extends Person { }
final 修饰属性
final 修饰一个变量时,此时的变量称为一个常量
final 修饰属性,可以考虑的赋值范围有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Orders { final int number = 1001 ; final String name; final boolean isFlag; { name = "李四" ; } public Orders () { isFlag = true ; } public Orders (boolean isFlag) { this .isFlag = isFlag; } }
final 修饰局部变量 当使用 final 修饰形参时,方法内将不能对这个形参做进一步修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class FianlTest05 { public static void main (String[] args) { FinalValue f = new FinalValue(); f.show("张三" ); } } class FinalValue { public void show (final String NAME) { final int AGE = 10 ; System.out.println(NAME + AGE); } }
抽象类和抽象方法的使用
抽象使用关键字 abstract
abstract 可以修饰类、方法
abstract 修饰类:
当使用 abstract 修饰一个类时,这个类就变成了了一个抽象类,这个抽象类将不能被实例化
抽象类中也一定有构造器,便于子类实例化时调用
当我们声明了一个抽象类之后,都会对应的声明一个抽象类的子类,让子类对象实例化,完成相关操作
abstract 修饰方法:
抽象方法中没有方法体
1 public abstract void show () ;
抽象方法所在的类一定是一个抽象类,但是一个抽象类中不一定有抽象方法
当子类继承抽象类之后,在子类中必须重写父类中所有的抽象方法,否则编译会出错
如果子类不想重写父类中的抽象方法,则子类也要声明成为一个抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 abstract class Person { public void eat () { System.out.println("吃饭" ); } public abstract void show () ; } abstract class Main extends Person { public abstract void task () ; } class Students extends Main { @Override public void task () { System.out.println("重写后的task方法" ); } @Override public void show () { System.out.println("重写后的show方法" ); } }
创建抽象类的匿名子类对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public class AnonymousTest02 { public static void main (String[] args) { Persons p = new Persons() { @Override public void show () { System.out.println("展示" ); } @Override public void eat () { System.out.println("吃好吃的" ); } }; methods(p); methods(new Persons() { @Override public void show () { System.out.println("展示" ); } @Override public void eat () { System.out.println("吃饭" ); } }); } public static void methods (Persons p) { p.show(); p.eat(); } } abstract class Persons { public abstract void show () ; public abstract void eat () ; }
模板方法的设计模式和应用场景 抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式
解决的问题:
当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以吧不确定的暴露出去,让子类去实现
换句话说,在软件开发中实现一个算法时,整体的步骤很固定、通用,这些步骤已经在父类中写好了,但是某些部分易变,易变的部分可以抽象出来,供不同的子类去实现。这就是一种模板模式
代码示例一:计算某个方法的执行总时长
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public class TemplateTest01 { public static void main (String[] args) { Template1 t = new Tool1(); t.spendTime(); Template1 t1 = new Tool2(); t1.spendTime(); } } abstract class Template1 { public void spendTime () { long time = System.currentTimeMillis(); code(); long endTime = System.currentTimeMillis(); System.out.println("代码花费:" + (endTime - time)); } public abstract void code () ; } class Tool1 extends Template1 { @Override public void code () { for (int i = 1 ; i <= 1000 ; i++) { if (i % 2 == 0 ) { System.out.println(i); } } } } class Tool2 extends Template1 { @Override public void code () { for (int i = 1 ; i <= 1000 ; i++) { if (i % 2 == 1 ) { System.out.println(i); } } } }
接口的定义和使用
接口使用 intreface
关键字来定义
Java中类和接口是两个并列结构
如何定义接口:定义接口中的成员
JDK7.0 之前只能定义常量和抽象方法
全局常量 public static final
,在书写可以忽略这些关键字,默认就是常量
抽象方法 public abstract
,在书写时可以忽略不计,默认就是抽象方法
JDK8.0,除了定义常量和抽象方法,也可以定义静态方法,默认方法
接口中不能定义构造器,意味着接口不能被实例化
Java开发中,通过让类去实现(implements
)某个接口的方式来使用接口
在类中我们要覆盖接口中的抽象方法,否则类不能被实例化,或者将父类定义成抽象类让子类去实现接口中的方法
接口的具体使用,体现了多态性
接口实际上可以看做是一种规范
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public class InterfaceTest01 { public static void main (String[] args) { System.out.println(Flyable.MAXSPEED); System.out.println(Flyable.MINSPEED); Plane p = new Plane(); p.fly(); p.stop(); } } interface Flyable { public static final int MAXSPEED = 7900 ; int MINSPEED = 1 ; public abstract void fly () ; void stop () ; } class Plane implements Flyable { @Override public void fly () { System.out.println("宇宙第一速度是:" + Flyable.MAXSPEED); } @Override public void stop () { System.out.println("停止方法" ); } }
接口的多实现和接口的多继承 Java类中可以实现多个接口,弥补了Java单继承的局限性
格式class AA extends BB implements CC,DD{ }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 interface eat { void eatShow () ; } interface speak { void speakShow () ; } class Person { String name; } class Student extends Person implements eat ,speak { @Override public void speakShow () { } @Override public void eatShow () { } }
接口与接口之间可以实现多继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class InterfaceTest03 { public static void main (String[] args) { Dd d = new Dd(); d.method1(); d.method2(); d.method3(); } } interface Aa { void method1 () ; } interface Bb { void method2 () ; } interface Cc extends Aa ,Bb { void method3 () ; } class Dd implements Cc { @Override public void method1 () { System.out.println("Aa方法中的method1" ); } @Override public void method2 () { System.out.println("Bb方法中的method2" ); } @Override public void method3 () { System.out.println("Cc方法中的method3" ); } }
接口满足多态的体现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class InterfaceTest04 { public static void main (String[] args) { UsbTest u = new UsbTest(); Phone p = new Phone(); u.transferData(p); } } interface Usb { void start () ; void stop () ; } class Phone implements Usb { @Override public void start () { System.out.println("开始传输数据" ); } @Override public void stop () { System.out.println("结束传输数据" ); } } class UsbTest { public void transferData (Usb usb) { usb.start(); System.out.println("具体传输细节" ); usb.stop(); } }
创建接口的匿名实现类的匿名对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 UsbTest u = new UsbTest(); Phone p = new Phone(); u.transferData(p); u.transferData(new Phone()); Usb p1 = new Usb() { @Override public void start () { System.out.println("开始传输数据" ); } @Override public void stop () { System.out.println("结束传输数据" ); } }; u.transferData(p1); u.transferData(new Usb() { @Override public void start () { System.out.println("开始传输数据" ); } @Override public void stop () { System.out.println("结束传输数据" ); } });
接口应用:代理模式 代理设计就是为其他对象提供一种代理以控制这个对象的访问。
代理模式的应用场景:
安全代理:屏蔽对真实对象的直接访问
远程代理:通过代理类处理远程方法的调用(RMI)
延迟加载:先加载轻量级的代理对象,真正需要时再加载真实对象
代理模式分类
静态代理:静态定义代理类
动态代理:动态生成代理类,JDK自带动态代理,需要反射等知识
通过明星和经纪人之间的关系来感受代理模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 public class InterfaceTest05 { public static void main (String[] args) { Proxy p = new Proxy(new RealStar()); p.confer(); p.signContract(); p.bookTicket(); p.sing(); p.collectMoney(); } } interface Star { void confer () ; void signContract () ; void bookTicket () ; void sing () ; void collectMoney () ; } class RealStar implements Star { @Override public void confer () { } @Override public void signContract () { } @Override public void bookTicket () { } @Override public void sing () { System.out.println("明星自己亲自唱歌~~" ); } @Override public void collectMoney () { } } class Proxy implements Star { private Star real; public Proxy (Star real) { this .real = real; } @Override public void confer () { System.out.println("经理人面谈" ); } @Override public void signContract () { System.out.println("经理人签合同" ); } @Override public void bookTicket () { System.out.println("经纪人订票" ); } @Override public void sing () { real.sing(); } @Override public void collectMoney () { System.out.println("经纪人收钱" ); } }
接口和类中出现同名变量时 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class InterfaceExer01 { public static void main (String[] args) { A a = new A(); a.show(); } } interface C { int x = 0 ; } class B { int x = 1 ; } class A extends B implements C { public void show () { System.out.println(super .x); System.out.println(C.x); } }
Double包装类比较大小 因为Double实现了Comparable接口,接口中有compareTo方法,可以用来比较大小
1 2 3 4 5 6 7 8 Double d1 = 1.2 ; Double d2 = 2.1 ; System.out.println(d1.compareTo(d2));
Java8中接口的新特性
Java8中接口内不仅能定义抽象方法,也可以定义静态方法
定义抽象方法、静态方法、默认方法格式如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public interface InterfaceTest { void method1 () ; static void method2 () { System.out.println("静态方法" ); } default void method3 () { System.out.println("默认方法" ); } }
静态方法和默认方法使用的规定
接口中定义的静态方法只能通过 接口.方法名();
的方式来调用
通过接口实现类的对象来调用接口中的方法,可以调用接口中的默认方法,如果实现类重写了接口中的默认方法,则调用的还是重写之后的方法
如果子类继承了父类并且实现了某个方法,则如果父类和接口中有同名同参的方法,那么在使用实现类去调用这个方法时,如果子类没有重写,那么调用的时父类中的方法 — 类优先原则
如果实现类实现了多个接口,多个接口之间存在同名同参的方法,那么将编译出错,方法之间会出现冲突,实现类必须要去重写多个接口之间的同名同参方法
可以使用 接口.supter.方法名();
的方式去直接调用接口中的方法
代码示例:
1.定义接口1 Compar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public interface Compar { public static void method1 () { System.out.println("Compar:静态方法" ); } public default void method2 () { System.out.println("Compar:默认方法" ); } default void method3 () { System.out.println("接口中的public可以忽略" ); } default void method4 () { System.out.println("接口1中的method4" ); } }
2.定义接口2 Compar2
1 2 3 4 5 public interface Compar2 { default void method4 () { System.out.println("接口2中的method4" ); } }
3.定义父类 SuperClass
1 2 3 4 5 public class SuperClass { public void method2 () { System.out.println("父类中和接口内重名的接口" ); } }
4.定义实现类和main
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class SupClass { public static void main (String[] args) { Sup s = new Sup(); s.method3(); Compar.method1(); s.method2(); s.method4(); } } class Sup extends SuperClass implements Compar ,Compar2 { public void method3 () { System.out.println("实现类中重写接口的方法" ); } @Override public void method4 () { Compar.super .method4(); Compar2.super .method4(); } }
内部类的分类 内部类:Java中允许在类A中声明类B,则B就是内部类,类A就是外部类
内部类的分类:
成员内部类(静态内部类,非静态内部类)
局部内部类(方法内、代码块内、构造器内)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class ManTest { static class Dog { } class Cat { } { class Fish { } } public ManTest () { class Chicken { } } public void show () { class Duck { } } }
成员内部类的特点 作为成员来说
可以外部类的结构
可以被static修饰
可以被4中权限修饰符修饰
作为一个类来说
类内部可以声明属性、方法、构造器、代码块等
可以被final修饰,表示这个类不能被继承
可以被abstract修饰,表示一个抽象内部类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class ManTest { String name = "李四" ; int number = 10 ; static int id; public void eat () { System.out.println("吃东西" ); } static class Dog { public void show () { System.out.println(id); } } class Cat { public void show () { System.out.println(ManTest.this .number); System.out.println(number); eat(); } } }
实例化成员内部类的方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Man { public static void main (String[] args) { ManTest.Dog dog = new ManTest.Dog(); dog.show(); ManTest m = new ManTest(); ManTest.Cat cat = m.new Cat () ; cat.show(); } }
局部内部类的使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class Man2 { public static void main (String[] args) { Catparable c = new Person().getCatparable(); c.speak(); } } interface Catparable { void speak () ; } class Person { public Catparable getCatparable () { class Cat implements Catparable { public void speak () { System.out.println("喵喵喵~" ); } } return new Cat(); } }
局部内部类使用的一个注意点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Persons { public void show () { int number = 10 ; final String name = "李四" ; class neibu { public void show () { System.out.println(number); } } } }