面向对象(上) 面向对象(中) 面向对象(下)
static:静态的
可以用来修饰的结构:主要用来修饰类的内部结构 属性、方法、代码块、内部类
static修饰属性:静态变量(或类变量)
属性,是否使用static修饰,又分为:静态属性(静态变量) vs 非静态属性(实例变量)实例变量:我们创建了类的多个对象,每个对象都独立的拥一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。
static修饰属性的其他说明: 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用静态变量的加载要早于对象的创建。由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。访问权限允许时,可不创建对象,直接被类调用 class Circle{ private double radius; public Circle(double radius){ this.radius=radius; } public double findArea(){ return Math.PI*radius*radius; } } 创建两个Circle对象 Circle c1=new Circle(2.0); //c1.radius=2.0 Circle c2=new Circle(3.0); //c2.radius=3.0Circle类中的变量radius是一个实例变量(instance variable),它属于类的每一个对象,不能被同一个类的不同对象所共享。
上例中c1的radius独立于c2的radius,存储在不同的空间。c1中的radius变化不会影响c2的radius,反之亦然。
想让一个类的所有实例共享数据,这时候就出现了类变量!
类变量应用举例
class Person { private int id; public static int total = 0; public Person() { total++; id = total; } public static void main(String args[]) { Person Tom = new Person(); Tom.id = 0; total = 100; // 不用创建对象就可以访问静态成员 } } public class StaticDemo { public static void main(String args[]) { Person.total = 100; // 不用创建对象就可以访问静态成员 //访问方式:类名.类属性,类名.类方法 System.out.println(Person.total); Person c = new Person(); System.out.println(c.total); //输出101 } }设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式免去我们自己再思考和摸索。就像是经典 的棋谱,不同的棋局,我们用不同的棋谱-”套路”
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
由于Java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public,又因为Java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static的,该方法接收一个String类型的数组参数,该数组中保存执行Java命令时传递给所运行的类的参数。
又因为main() 方法是静态的,我们不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情况,我们在之前的例子中多次碰到。
静态初始化块举例
class Person { public static int total; static { total = 100; System.out.println("in static block!"); } } public class PersonTest { public static void main(String[] args) { System.out.println("total = " + Person.total); System.out.println("total = " + Person.total); } }总结:程序中成员变量赋值的执行顺序
常量名要大写,内容不可修改。
static final 用来修饰属性:全局常量随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
用abstract关键字来修饰一个类,这个类叫做抽象类。用abstract来修饰一个方法,该方法叫做抽象方法。 抽象方法:只有方法的声明,没有方法的实现。以分号结束: 比如:public abstract void talk();含有抽象方法的类必须被声明为抽象类。抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。不能用abstract修饰变量、代码块、构造器;不能用abstract修饰私有方法、静态方法、final的方法、final的类。抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。
举例:
在航运公司系统中,Vehicle类需要定义两个方法分别计算运输工具的燃料效率和行驶距离。问题:卡车(Truck)和驳船(RiverBarge)的燃料效率和行驶距离的计算方法完全不同。Vehicle类不能提供计算方法,但子类可以。解决方案 Java允许类设计者指定:父类声明一个方法但不提供实现,该方法的实现由子类提供。 这样的方法称为抽象方法。有一个或更多抽象方法的类称为抽象类。Vehicle是一个抽象类,有两个抽象方法。 public abstract class Vehicle { public abstract double calcFuelEfficiency(); //计算燃料效率的抽象方法 public abstract double calcTripDistance(); //计算行驶距离的抽象方法 } public class Truck extends Vehicle { public double calcFuelEfficiency() { //写出计算卡车的燃料效率的具体方法 } public double calcTripDistance() { //写出计算卡车行驶距离的具体方法 } } public class RiverBarge extends Vehicle { public double calcFuelEfficiency() { //写出计算驳船的燃料效率的具体方法 } public double calcTripDistance() { //写出计算驳船行驶距离的具体方法 } }注意:抽象类不能实例化 new Vihicle()是非法的
举例:
接口(interface)是抽象方法和常量值定义的集合。接口的特点: 用interface来定义。接口中的所有成员变量都默认是由public static final修饰的。接口中的所有抽象方法都默认是由public abstract修饰的。接口中没有构造器。接口采用多继承机制。 接口定义举例 :左右等价 定义Java类的语法格式:先写extends,后写implements class SubClass extends SuperClass implements InterfaceA{ } 一个类可以实现多个接口,接口也可以继承其它接口。实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。接口的主要用途就是被实现类实现。(面向接口编程)与继承关系类似,接口与实现类之间存在多态性接口和类是并列关系,或者可以理解为一种特殊的类。从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义(JDK7.0及之前),而没有变量和方法的实现。应用举例:
interface Runner { public void start(); public void run(); public void stop(); } class Person implements Runner { public void start() { // 准备工作:弯腰、蹬腿、咬牙、瞪眼 // 开跑 } public void run() { // 摆动手臂 // 维持直线方向 } public void stop() { // 减速直至停止、喝水。 } }实现类SubAdapter必须给出接口SubInterface以及父接口MyInterface中 所有方法的实现。否则,SubAdapter仍需声明为abstract的。
概述:
代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。
应用场景: 安全代理:屏蔽对真实角色的直接访问。远程代理:通过代理类处理远程方法调用(RMI)延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象比如你要开发一个大文档查看软件,大文档中有大的图片,有可能一个图片有100MB,在打开文件时,不可能将所有的图片都显示出来,这样就可以使用代理模式,当需要查看图片时,用proxy来进行大图片的打开。 分类 静态代理(静态定义代理类)动态代理(动态生成代理类)JDK自带的动态代理,需要反射等知识在开发中,常看到一个类不是去继承一个已经实现好的类,而是要么继承抽象类,要么实现接口。
Java 8中,你可以为接口添加静态方法和默认方法。从技术角度来说,这是完全合法的,只是它看起来违反了接口作为一个抽象定义的理念。
静态方法: 使用 static 关键字修饰。可以通过接口直接调用静态方法,并执行其方法体。我们经常在相互一起使用的类中使用静态方法。你可以在标准库中找到像Collection/Collections或者Path/Paths这样成对的接口和类。
默认方法: 默认方法使用 default 关键字修饰。可以通过实现类对象来调用。我们在已有的接口中提供新方法的同时,还保持了与旧版本代码的兼容性。比如:java 8 API中对Collection、List、Comparator等接口提供了丰富的默认方法
public interface AA { double PI = 3.14; public default void method() { System.out.println("北京"); } default String method1() { return "上海"; } public static void method2() { System.out.println("hello lambda !"); } }若一个接口中定义了一个默认方法,而另外一个接口中也定义了一个同名同参数的方法(不管此方法是否是默认方法),在实现类同时实现了这两个接口时,会出现:接口冲突。 解决办法:实现类必须覆盖接口中同名同参数的方法,来解决冲突。
若一个接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非抽象方法,则不会出现冲突问题。因为此时遵守:类优先原则。接口中具有相同名称和参数的默认方法会被忽略。
interface Filial {// 孝顺的 default void help() { System.out.println("老妈,我来救你了"); } } interface Spoony {// 痴情的 default void help() { System.out.println("媳妇,别怕,我来了"); } } class Man implements Filial, Spoony { @Override public void help() { System.out.println("我该怎么办呢?"); Filial.super.help(); Spoony.super.help(); } }当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。
在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
Inner class一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。
Inner class的名字不能与包含它的外部类类名相同;分类: 成员内部类(static成员内部类和非static成员内部类)
局部内部类(不谈修饰符)、匿名内部类
成员内部类作为类的成员的角色:
和外部类不同,Inner class还可以声明为private或protected;可以调用外部类的结构Inner class 可以声明为static的,但此时就不能再使用外层类的非static的成员变量;成员内部类作为类的角色:
可以在内部定义属性、方法、构造器等结构可以声明为abstract类 ,因此可以被其它的内部类继承可以声明为final的编译以后生成OuterClass$InnerClass.class字节码文件(也适用于局部内部类)【注意】
非static的成员内部类中的成员不能声明为static的,只有在外部类或static的成员内部类中才可声明static成员。外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”的方式成员内部类可以直接使用外部类的所有成员,包括私有的数据当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的(1)
class Outer { private int s; public class Inner { public void mb() { s = 100; System.out.println("在内部类Inner中s=" + s); } } public void ma() { Inner i = new Inner(); i.mb(); } } public class InnerTest { public static void main(String args[]) { Outer o = new Outer(); o.ma(); } }(2)
public class Outer { private int s = 111; public class Inner { private int s = 222; public void mb(int s) { System.out.println(s); // 局部变量s System.out.println(this.s); // 内部类对象的属性s System.out.println(Outer.this.s); // 外部类对象属性s } } public static void main (String args[]){ Outer a = new Outer(); Outer.Inner b = a.new Inner(); b.mb(333); } } } } 如何声明局部内部类 class 外部类 { 方法() { class 局部内部类 { } } { class 局部内部类 { } } } 如何使用局部内部类 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型