面向对象高级--java

  • 类变量和类方法
  • 类变量
  • 什么是类变量
  • 类变量的使用细节
  • 类方法
  • 类方法的使用细节
  • 理解main方法和语法
  • 深入理解main方法
  • 代码块
  • 基本介绍
  • 使用细节
  • 单例设计模式
  • 饿汉式
  • 懒汉式
  • final关键字
  • 基本介绍
  • 使用细节
  • 抽象类
  • 使用细节
  • 抽象类最佳实践--模板设计模式
  • 接口
  • 基本介绍
  • 注意事项
  • 接口和继承对比
  • 接口与多态
  • 内部类
  • 基本介绍
  • 四种内部类
  • 局部内部类
  • 匿名内部类
  • 成员内部类
  • 静态内部类


类变量和类方法

类变量

类变量又叫做静态变量,关于它存放的位置有不同的说法,但是共识有两点:
1.static变量是同一个类中所有对象共享。
2.static变量在类加载的时候就生成了。

什么是类变量

类变量也叫静态变量或者静态属性,是该类的所有对象共享的一个变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。
如何定义类变量:
访问修饰符 static 数据类型 变量名;
静态变量的访问修饰符的访问权限和范围和普通属性是相同的。
如何访问类变量:
类名.类变量名
或者对象名.类变量名

类变量的使用细节

1.类变量是在类加载的时候就初始化了,也就是说,即使没有创建对象,也可以使用类变量。
2.类变量的生命周期是随类的加载开始,随着类消亡而销毁。

类方法

基本介绍:
类方法也叫静态方法。
形式如下:
访问修饰符 static 数据返回类型 方法名(){}
(前提是满足访问修饰符的权限)
类方法的调用:
类名.类方法名
类方法的经典应用场景:
当方法中不涉及任何和对象相关的成员,则可以将方法设计成类方法,这类方法一般是工具,是一些通用的方法,例如:math类,arrays类等等。

类方法的使用细节

1.类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区,类方法中无this的参数,普通方法中隐含着this的参数。
2.类方法中不允许使用和对象有关的关键字,比如this和super,普通方法可以。
3.静态方法只能访问静态成员,非静态方法既可以访问静态成员,也可以访问非静态成员。
(必须遵守访问权限)

理解main方法和语法

深入理解main方法

解释main方法的形式:public static void main(String[] args){ }

1.main方法是虚拟机调用的。

2.java虚拟机需要调用该类的main()方法,所以mian()方法的访问权限必须是public .

2.java虚拟机在执行main()方法时不必调用对象,因此该方法是static。

3.该方法接受String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数

java中常用的路网算法库是什么_代码块


main方法同样遵循静态方法的规定,不能调用本类中的非静态成员,如果想要调用,必须先new一个对象,然后通过对象调用。

代码块

基本介绍

代码块又称为初始化块,属于类中的成员,即是类的一部分,类似与方法,将逻辑语句封装在方法体内,通过{}包围起来。
但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或者类显式调用,而是加载类时,或创建对象时,隐式调用。
基本语法
修饰符{
代码
};
1.修饰符可写可不写,写的话只能选择static
2.代码块分为两类,使用static修饰的为静态代码块,没有static修饰的为普通代码块。
3.逻辑语句可以为任何逻辑语句。
4. ;可以写上,也可以省略。
代码块的好处:
1.相当于另一种形式的构造器,对构造器的补充,可以做初始化的操作。
2.如果多个构造器中有重复的语句,可以将相同的语句放入代码块中,提高代码的复用性。

使用细节

1.static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次,如果是普通代码块,每创建一个对象,就执行一次。
类什么时候被加载
1.创建对象实例时
2.创建子类对象实例时,父类也会被加载
3.使用类的静态成员时

2.普通代码块在使用类的静态成员时,不会被调用。
3.创建一个对象时,在一个类中调用顺序是:
(1)调用静态代码块和静态属性初始化。(注意:静态代码块和静态属性初始化的调用优先级相同,如果同时存在,则按照它们的顺序执行)。
(2)调用普通代码块和普通属性初始化。(注意:普通代码块和普通属性初始化的调用优先级相同,如果同时存在,则按照它们的顺序执行)。
(3)调用构造方法。

4.构造器的最前面其实隐含了super()和调用普通代码块,静态代码块和静态属性初始化在类加载时就执行完毕了,因此是优于构造器和普通代码块执行的。
5.创建一个子类对象时(继承关系),它们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:
1.父类的静态代码块和静态属性初始化。
2.子类的静态代码块和静态属性初始化。
3.父类的普通代码块和普通属性初始化。
4.父类的构造方法。
5.子类的普通代码块和普通属性初始化。
6.子类的构造方法。

单例设计模式

饿汉式

步骤如下:
1.将构造器私有化。
2.在类的内部创建一个对象。
3.向外暴露一个静态的公共方法。
代码如下:

class GirlFriend{
    private String name;
    private static GirlFriend gf = new GirlFriend("小红");
    private GirlFriend(String name) {
        this.name = name;
    }
    public static GirlFriend getInstance(){
        return gf;
    }
    
}

这种方式在类加载的时候就创建了一个对象,即使你没有使用这个对象,因此叫做饿汉式。

懒汉式

懒汉式只有在使用者想要使用时才会创建一个对象。

//懒汉式
class Cat{
    private String name;
    private static Cat cat;
    private Cat(String name) {
        this.name = name;
    }
    public static Cat getInstance(){
        if(cat == null){
            cat = new Cat("小黄");
        }
        return cat;
    }
}

final关键字

基本介绍

final可以修饰类,属性,方法,局部变量。在下列情况下。可能会使用到final:
1.当不希望类被继承时,可以使用final修饰。
2.当不希望父类的某个方法被子类重写时,可以使用final关键字修饰。
3.当不希望类的某个属性或者局部变量的值被修改时,可以使用final修饰。

使用细节

1.final修饰的属性又叫做常量,一般用XX_XX来命名。
2.final修饰的属性定义时必须赋初值,并且以后不能更改,赋值可以在以下几种位置:
(1).定义时
(2).构造器中
(3).代码块中
3.如果final修饰的属性是静态的,则初始化的位置只能是
(1).定义时
(2).静态代码块中
3.如果类不是final类,但是含有final方法,该方法虽然不能够重写,但是可以继承。
4.final不能修饰构造器。
5.final和static往往搭配使用,效率更好,不会导致类加载,因为底层编译器做了优化处理。
6.包装类(String,Double,Float,Boolean)等都是final类,不能被继承。

抽象类

基本介绍:
当父类的某个方法不确定时,可以用abstract关键字来修饰该方法,这个方法就是抽象方法,用abstract修饰该类就是抽象类。一般来说,抽象类会有子类继承,通过子类来实现抽象类。

abstract class  Dog{
    public abstract void eat();
}

使用细节

1.抽象类不能够实例化,即不能创造对象。
2.抽象类不一定要包含abstract方法。
3.一旦包含了abstract方法,这个类必须声明为抽象类。
4.abstract只能修饰类和方法,不能修饰其他的。
5.抽象类中可以有任意成员,它的本质还是类。
6.如果一个类继承了抽象类,那么他必须实现抽象类的所有抽象方法,或者也声明为抽象类。
7.抽象方法不能使用private,final,static来修饰,因为这三个关键字都是和重写违背的。

抽象类最佳实践–模板设计模式

接口

基本介绍

接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些类写出来。

语法:

interface 接口名{
//属性
//方法
}

在接口里,抽象方法可以省略abstract

class 类名 implements 接口{
//自己属性
//自己方法
//必须实现接口的抽象方法
}

总结:
在JDK7.0之前,接口里的方法都是抽象方法,
在JDK8.0及之后,接口里可以有静态方法,默认方法,也就是说接口里可以有方法的具体实现。

//默认实现方法需要有default
default public void Hi(){
	System.out.println("hi ");
}

注意事项

1.接口不能被实例化。

2.接口中所有的方法是public 方法,接口中抽象方法可以不使用abstract修饰。

3.一个普通类实现接口,必须实现接口中所有的抽象方法。
可以使用快捷键alter+enter

4.如果是抽象类实现接口,可以不用实现接口中的方法。

5.一个类可以同时实现多个接口。

6.接口中的属性,只能是final的,而且是public static final修饰符,比如int n = 1;实际上是public static final int n = 1;(属性必须进行初始化)

7.接口中的属性的访问形式(接口名.属性名)

8.接口不能继承其他的类,但是可以继承其他的多个接口。(extends)

9.接口的修饰符只能是public 和默认,这点和类的修饰符是相同的。

10接口中的属性访问

interface A{
	int n =1;
}
class B implements A{
	
}
main方法中{
	B b  = new B();
	b.n;
	A.n;
	B.n;
	//这三种方式都可以访问A中的属性
}

接口和继承对比

当子类继承了父类,就自动的拥有父类的功能,如果子类需要扩展功能,可以通过实现接口的方式来扩展,可以理解为,实现接口是对JAVA单继承机制的一种补充。

(1)接口和继承解决的问题不同
继承的价值主要在于:
解决代码的复用性和可维护性。
接口的价值主要在于:
设计,设计好各种规范(方法),让其他类去实现这些方法,即更加的灵活。

(2)接口比继承更加灵活,继承是满足is-a的关系,而接口只需满足like-a的关系

(3)接口在一定程度上实现代码的解耦。

接口与多态

1.接口的多态性

public class interfacePoly {
    public static void main(String[] args) {
        //接口类型的变量a可以指向实现了接口的类的对象实例
        IF a = new A();
        a = new B();
    }
}
interface IF{}
class A implements IF{}
class B implements IF{}

2.多态数组

public class interFacePolyArr {
    public static void main(String[] args) {
        usb[] usbs = new usb[2];
        usbs[0] = new phone();
        usbs[1] = new camera();
        for (int i = 0; i < 2; i++) {
            usbs[i].work();
            if(usbs[i] instanceof 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("相机工作中");
    }
}

3.多态传递

public class interFacePolyPass {
    public static void main(String[] args) {
        D d = new teacher();
        //D继承了C接口,那么就相当于teacher也实现了C接口,可以有下面的定义
        C c = new teacher();
    }
}
interface C{}
interface D extends C{}
class teacher implements D{}

内部类

基本介绍

一个类的内部又完整的嵌套了另一个类结构,嵌套的类成为内部类,被嵌套的类成为外部类。类的五大成员包括属性,方法,构造器,代码块,内部类,内部类的最大特点就是可以直接访问私有属性,并且可以实现类与类之间的包含关系。

基本语法:

class Outer{ //外部类
	class Inner{ //内部类
	}
}

四种内部类

局部内部类

定义在外部类局部位置上,比如方法内,有类名。

使用细节:
1.可以直接访问外部类的所有成员,包括私有的。

2.不能添加访问修饰符,因为它的地位就是一个局部变量,局部变量是不能使用修饰符的,但是可以使用final修饰,因为局部变量也可以使用final.

3.作用域:仅仅在定义它的方法或者代码块内部。

4.局部内部类—访问—>外部类成员(访问方式:直接访问)

5.外部类—访问---->局部内部类成员
访问方式:创建对象,在访问(注意:必须在作用域内部)

class AA{
	private int n1 = 10;
	private void m1(){
		System.out.println("m1被调用");
	}
	public void n1(){
		class inner{
			public int n1 = 100;
			public void f1(){
				System.out.println(n1);
				System.out.println("外部类的n1= " + AA.this.n1);
				m1();
			}
		}
		inner inner01 = new inner();
		inner01.f1();	
	}
}

6.外部其它类不能调用局部内部类,因为局部内部类有使用范围.

7.如果外部类和局部内部类的成员重名时,遵循就近原则,如果想要访问外部类的成员,可以使用(外部类名.this.成员名)去访问.

匿名内部类

定义在外部类局部位置上,比如方法内,没有类名。
主要有4点:1.本质还是类 2.内部类 3.该类没有名字 4 .还是一个对象

基本语法:

new 类或者接口(参数列表){
	类体
};
class Untitled {
	public static void main(String[] args) {
		f1 f = new f1();
		f.method();
	}
}
class f1{
	public void method(){
		//a的编译类型 A   运行类型  匿名内部类即f1$1
		//jdk在底层创建 匿名内部类  f1$1 ,并且立刻创建了它的实例,把地址返回给a
		//匿名内部类使用一次就不能再使用,但a可以连续使用
		A a = new A(){
			public void cry(){
				System.out.println("哈哈哈");
			}
		};
		a.cry();
	}
}
interface A{
	void cry();
}
class Untitled {
	public static void main(String[] args) {
		f1 f = new f1();
		f.method();
	}
}
class f1{
	public void method(){
		//基于类的匿名内部类
		Father father = new Father("Jack"){
			public void test(){
				System.out.println("匿名内部类的test被调用");
			}
		};
		father.test();
	}
}
class Father{
	public Father(String name){
		System.out.println("name= " + name);
	}
	public void test(){
		System.out.println("Father的test被调用");
	}
}

使用细节:
1.匿名内部类既是一个类的定义,同时也是一个对象,因此调用匿名内部类的方法有两种情况。
上面的例子是其中一种,下面展示另外一种:

new Father("Jack"){
	public void test(){
		System.out.println("匿名内部类的test被调用");
		}
}.test();

2.可以直接访问外部类的所有成员。

3.不能添加访问修饰符,因为它的地位就是一个局部变量。

4.作用域:仅仅在定义它的代码块或者方法中。

5.外部其它类不能调用匿名内部类,因为匿名内部类有使用范围.

6.如果外部类和匿名内部类的成员重名时,遵循就近原则,如果想要访问外部类的成员,可以使用(外部类名.this.成员名)去访问.
实践:
1.当做实参直接传递,简洁高效。

public class NiMingClass {
    public static void main(String[] args) {
        Abc(new AB() {//匿名内部类本质上也是一个对象
            @Override
            public void show() {
                System.out.println("这是一幅世界名画");
            }
        });
    }
    public static void Abc(AB ab){
        ab.show();
    }
}
interface AB{
    void show();
}

成员内部类

成员内部类是定义在外部类的成员位置,并且没有static修饰

使用细节:
1.可以直接访问外部类的所用成员,包括私有的。

public class MemberOuterClass {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.Abc();
        //第一种方式
        Outer.MemberOuter01 member = outer.new MemberOuter01();
        //第二种方式,在外部类写一个方法返回
        Outer.MemberOuter01 member01 = outer.t();
        
    }
}
class Outer{
    private int n =1;
    public String name = "张三";
    class MemberOuter01{
        public void say(){
            System.out.println("n= " + n + " name=" + name);
        }
    }
    public void Abc(){
        MemberOuter01 memberOuter01 = new MemberOuter01();
        memberOuter01.say();
    }
    public MemberOuter01 t(){
        return new MemberOuter01();
    }
}

2.可以添加任意访问修饰符(public ,protected , 默认 , privated ),因为它的地位就是一个成员。

3.作用域:和其它外部类的成员一样,为整个类体。

4.成员内部类访问外部类的成员-----直接访问。

5.外部类访问成员内部类的成员------先创建对象,在进行访问

6.外部其他类访问成员内部类有两种方式,代码如上:

7.如果外部类的成员与内部类的成员名字重复时,内部类访问时,遵循就近原则,如果想要访问外部类的成员,可以使用(外部类名.this.成员名)。

静态内部类

静态内部类是定义在外部类的成员位置,有static修饰。

使用细节:
1.可以直接使用外部类的所有静态成员,包括私有的,但是不能访问非静态成员。

2.可以添加任意访问修饰符,(public , protected , privated , 默认),它的地位就是一个成员。

3.作用域:同其他的成员,为整个类体

4.外部其他类访问静态内部类的方式有两种:

public class StaticInnerClass {
    public static void main(String[] args) {
        InnerClass.hi innerClass = new InnerClass.hi();
        innerClass.say();
        System.out.println("========");
        InnerClass.hi innerClass02 = new InnerClass().m1();
        innerClass02.say();
    }
}
class InnerClass{
    public int n1 = 10;
    public static String name = "李四";
    static class hi{
        public void say(){
            System.out.println(name);
        }
    }
    public hi m1(){
        return new hi();
    }

}

5…如果外部类的成员与内部类的成员名字重复时,内部类访问时,遵循就近原则,如果想要访问外部类的成员,可以使用(外部类名.成员名)。