Java面向对象《三》

一、关键字static

1、使用范围:在Java类中,可用static修饰属性、方法、代码块、内部类

2、被修饰的成员特点:

1)随着类的加载而加载

2)优先于对象存在

3)修饰的成员,被所有对象所共享

4)访问权限允许时,可不创建对象,直接被类调用

类变量内存解析(下图中的String字符串应该存放在方法区中,我们为了简化就把String字符串放在了堆中):

3、类方法

注意:

1)没有对象的实例时,可以用类名.方法名()的形式访问由static修饰的类方法。

2)在static方法内部只能访问类的static修饰的属性或方法,不能访问类的非static的结构。

3)因为不需要实例就可以访问static方法,因此static方法内部不能有this。(也 不能有super ? YES!)

4)static修饰的方法不能被重写

二、单例设计模式

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对 某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。 如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构 造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生 类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无 法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象, 静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象 的变量也必须定义成静态的。

1、单例(Singleton)设计模式-饿汉式

class Singleton {
// 1.私有化构造器
private Singleton() {
}
// 2.内部提供一个当前类的实例
// 4.此实例也必须静态化
private static Singleton single = new Singleton();
// 3.提供公共的静态的方法,返回当前类的对象
public static Singleton getInstance() {
return single;
}
}

2、单例(Singleton)设计模式-懒汉式(懒汉式暂时还存在线 程安全问题,讲到多 线程时,可修复)

class Singleton {
// 1.私有化构造器
private Singleton() {
}
// 2.内部提供一个当前类的实例
// 4.此实例也必须静态化
private static Singleton single;
// 3.提供公共的静态的方法,返回当前类的对象
public static Singleton getInstance() {
if(single == null) {
single = new Singleton();
}
return single;
}
}

单例设计模式优点:由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的 产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可 以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方 式来解决。

三、main()方法语法

1、由于Java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是 public,又因为Java虚拟机在执行main()方法时不必创建对象,所以该方法必须 是static的,该方法接收一个String类型的数组参数,该数组中保存执行Java命令 时传递给所运行的类的参数。

2、又因为main() 方法是静态的,我们不能直接访问该类中的非静态成员,必须创 建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情 况,我们在之前的例子中多次碰到。

五、代码块

1、作用:对Java类或对象进行初始化

2、分类:一个类中代码块若有修饰符,则只能被static修饰,称为静态代码块 (static block),没有使用static修饰的,为非静态代码块。

3、static代码块通常用于初始化static的属性

4、静态代码块:用static 修饰的代码块

1). 可以有输出语句。

2). 可以对类的属性、类的声明进行初始化操作。

3). 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。

4). 若有多个静态的代码块,那么按照从上到下的顺序依次执行。

5). 静态代码块的执行要先于非静态代码块。

6). 静态代码块随着类的加载而加载,且只执行一次。

5、非静态代码块:没有static修饰的代码块

1). 可以有输出语句。

2). 可以对类的属性、类的声明进行初始化操作。

3). 除了调用非静态的结构外,还可以调用静态的变量或方法。

4). 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。

5). 每次创建对象的时候,都会执行一次。且先于构造器执行。

6、程序中成员变量赋值的顺序

声明成员变量的默认初始化--------->显式初始化、多个初始化块依次被执行(同级别下按先后顺序执行)---------->构造器再对成员进行初始化操作------------>通过”对象.属性”或”对象.方法”的方式,可多次给属性赋值

四、final关键字

在Java中声明类、变量和方法时,可使用关键字final来修饰,表示“最终的”。

1)final标记的类不能被继承。提高安全性,提高程序的可读性。

2)final标记的方法不能被子类重写。

3)final标记的变量(成员变量或局部变量)即称为常量。名称大写,且只 能被赋值一次。

final标记的成员变量必须在声明时或在每个构造器中或代码块中显式赋 值,然后才能使用。

4)static final:全局常量

7、抽象类与抽象方法

1、用abstract关键字来修饰一个类,这个类叫做抽象类。

2、用abstract来修饰一个方法,该方法叫做抽象方法。

抽象方法:只有方法的声明,没有方法的实现。以分号结束: 比如:public abstract void talk();

3、含有抽象方法的类必须被声明为抽象类。

4、抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重 写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍 为抽象类。

5、不能用abstract修饰变量、代码块、构造器

6、不能用abstract修饰私有方法、静态方法、final的方法、final的类。

abstract class ppeople{
    ppeople(){
        System.out.println("people is constructing");
    }
    public int age;
}
class sstudent extends ppeople{
    sstudent(){
        System.out.println("student is constructing");
    }
}
public class test1 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        sstudent p = new sstudent();
    }
}
/*输出
 * people is constructing
 * student is constructing
 * */

7、抽象类的匿名子类对象

abstract class ppeople{
    public abstract void test1();
    public abstract void test2();
}
public class test1 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //创建了一个匿名子类的对象
        ppeople p = new ppeople() {

            @Override
            public void test1() {
                // TODO Auto-generated method stub
                System.out.println("11111");
            }
            @Override
            public void test2() {
                // TODO Auto-generated method stub
                System.out.println("222222");
            }
        };
        //相当于多态
        p.test1();
        p.test2();
    }
}
/*输出
 * 11111
 * 222222
 * */

五、模板方法设计模式

抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。

解决的问题:

1)当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以 把不确定的部分暴露出去,让子类去实现。

2)换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用, 这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽 象出来,供不同子类实现。这就是一种模板模式。

六、接口(Interface)

1、接口(interface)是抽象方法和常量值定义的集合。

2、接口的特点

1)用interface来定义。

2)接口中的所有成员变量都默认是由public static final修饰的。

3)接口中的所有抽象方法都默认是由public abstract修饰的。

4)接口中没有构造器。

5)接口采用多继承机制。

3、定义Java类的语法格式:先写extends,后写implements(class SubClass extends SuperClass implements InterfaceA{ })

4、一个类可以实现多个接口,接口也可以继承其它接口。

5、实现接口的类中必须提供接口中所有方法的具体实现内容,方可实 例化。否则,仍为抽象类。

6、接口的主要用途就是被实现类实现。(面向接口编程)

7、与继承关系类似,接口与实现类之间存在多态性

8、接口和类是并列关系,或者可以理解为一种特殊的类。从本质上讲, 接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义 (JDK7.0及之前),而没有变量和方法的实现。

//一个类可以实现多个无关的接口
interface Runner { public void run();}
interface Swimmer {public double swim();}
class Creator{public int eat(){…}} 
class Man extends Creator implements Runner ,Swimmer{
public void run() {……}
public double swim() {……}
public int eat() {……}
}
//与继承关系类似,接口与实现类之间存在多态性
public class Test{
public static void main(String args[]){
Test t = new Test();
Man m = new Man();
t.m1(m);
t.m2(m);
t.m3(m);
}
public String m1(Runner f) { f.run(); }
public void m2(Swimmer s) {s.swim();}
public void m3(Creator a) {a.eat();}
}
interface MyInterface{
String s=“MyInterface”;
public void absM1();
}
interface SubInterface extends MyInterface{
public void absM2();
}
public class SubAdapter implements SubInterface{
public void absM1(){System.out.println(“absM1”);}
public void absM2(){System.out.println(“absM2”);}
}
实现类SubAdapter必须给出接口SubInterface以及父接口MyInterface中
所有方法的实现。否则,SubAdapter仍需声明为abstract的。
//接口实现多态
interface ppeople{
    public abstract void test1();
    public abstract void test2();
}
class sstudent implements ppeople{
    @Override
    public void test1() {
        // TODO Auto-generated method stub
        System.out.println("11111");
    }
    @Override
    public void test2() {
        // TODO Auto-generated method stub
        System.out.println("22222");
    }
}
public class test1 {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ppeople p = new sstudent();
        //相当于多态
        p.test1();
        p.test2();
    }
}
/*输出
 * 11111
 * 222222
 * */

9、接口的应用:代理模式

代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问

示例:

interface Network {
public void browse();
}
// 被代理类
class RealServer implements Network {
@Override
public void browse() {
System.out.println("真实服务器上
网浏览信息");
}
}
// 代理类
class ProxyServer implements Network {
private Network network;
public ProxyServer(Network network) {
this.network = network;
}
public void check() {
System.out.println("检查网络连接等操作");
}
public void browse() {
check();
network.browse();
}
}
public class ProxyDemo {
public static void main(String[] args) {
Network net = new ProxyServer(new
RealServer());
net.browse();
}
}

10、接口和抽象类之间的对比

interface A {
int x = 0;
}
class B {
int x = 1;
}
class C extends B implements A {
public void pX() {
System.out.println(x);  出错
/*
这个x会报错,因为编译器不知道这个x时接口的x还是B类的x
如果B继承A,C继承B,且A、B、C都有自己的一个变量x,那么就会根据就近原则调用x

*/
System.out.println(super.x); 调用B类的
System.out.println(A.x);   调用A类的
}
public static void main(String[] args) {
new C().pX();
}
}
interface Playable {
void play();
}
interface Bounceable {
void play();
}
interface Rollable extends Playable, 
Bounceable {
Ball ball = new Ball("PingPang");
}
class Ball implements Rollable {
private String name;
public String getName() {
return name;
}
public Ball(String name) {
this.name = name;
}
public void play() { //两个接口中都有play方法,这样写的话这个方法算作两个,不会报错
//ball是接口中定义的变量,接口中变量默认是final类型,不可以改变
ball = new Ball("Football"); //错误
System.out.println(ball.getName());
}
}

11、Java8关于接口的改进

Java 8中,你可以为接口添加静态方法和默认方法。从技术角度来说,这是完 全合法的,只是它看起来违反了接口作为一个抽象定义的理念。

静态方法:使用 static 关键字修饰。可以通过接口直接调用静态方法,并执行 其方法体。我们经常在相互一起使用的类中使用静态方法。你可以在标准库中 找到像Collection/Collections或者Path/Paths这样成对的接口和类。

默认方法:默认方法使用 default 关键字修饰。可以通过实现类对象来调用。 我们在已有的接口中提供新方法的同时,还保持了与旧版本代码的兼容性。 比如:java 8 API中对Collection、List、Comparator等接口提供了丰富的默认 方法。

注意:

1)若一个接口中定义了一个默认方法,而另外一个接口中也定义了一个同名同 参数的方法(不管此方法是否是默认方法),在实现类同时实现了这两个接 口时,会出现:接口冲突。

解决办法:实现类必须覆盖接口中同名同参数的方法,来解决冲突。

2)若一个接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非 抽象方法,则不会出现冲突问题。因为此时遵守:类优先原则。接口中具有 相同名称和参数的默认方法会被忽略。

七、内部类

1、成员内部类作为类的成员的角色:

1)和外部类不同,Inner class还可以声明为private或protected;

2)可以调用外部类的结构

3)Inner class 可以声明为static的,但此时就不能再使用外层类的非static的成员 变量;

2、成员内部类作为类的角色:

1)可以在内部定义属性、方法、构造器等结构

2)可以声明为abstract类 ,因此可以被其它的内部类继承

3)可以声明为final

4)编译以后生成OuterClass$InnerClass.class字节码文件(也适用于局部内部类

【注意】

1). 非static的成员内部类中的成员不能声明为static的,只有在外部类或static的成员 内部类中才可声明static成员。

2). 外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”的方式

3). 成员内部类可以直接使用外部类的所有成员,包括私有的数据

4). 当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的 

示例:

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();
}
}
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);
}
}

3、如何声明局部内部类

4、如何使用局部内部类

1)只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方 都不能使用该类

2)但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类 的父类或父接口类型 

5、局部内部类的特点

1)内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但 是前面冠以外部类的类名和$符号,以及数字编号。

2)只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方 都不能使用该类。

3)局部内部类可以使用外部类的成员,包括私有的。

4)局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局 部变量的声明周期不同所致。

5)局部内部类和局部变量地位类似,不能使用public,protected,缺省,private

6)局部内部类不能使用static修饰,因此也不能包含静态成员

6、匿名内部类

1)匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一 个实例。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或 实现一个类。

2)格式: new 父类构造器(实参列表)|实现接口(){ //匿名内部类的类体部分 }

3)匿名内部类的特点:  匿名内部类必须继承父类或实现接口  匿名内部类只能有一个对象  匿名内部类对象只能使用多态形式引用

示例:

interface A{
public abstract void fun1();
}
public class Outer{
public static void main(String[] args) {
new Outer().callInner(new A(){
//接口是不能new但此处比较特殊是子类对象实现接口,只不过没有为对象取名
public void fun1() {
System.out.println(“implement for fun1");
}
});// 两步写成一步了
}
public void callInner(A a) {
a.fun1();
}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

编译以后生成OuterClass$InnerClass.class字节码文件(也适用于局部内部类)

posted @ 2021-05-03 15:50  kongbursi  阅读(53)  评论(0编辑  收藏  举报