zoukankan      html  css  js  c++  java
  • Java 基础-类与面向对象

    Object 类(java.lang.Object)是所有 Java 类的直接或间接父类。

    成员方法及变长参数

    方法定义:

    [public | protected | private] [static] [final] [abstract] [native] [synchronized]
    返回类型 方法名([参数列表][throws exceptionList] {
    	// 方法体
    }
    
    • static:表示这是一个类方法(静态方法),不需实例化即可调用
    • final:表示这是一个终结方法,不可覆盖
    • abstract:抽象方法,只有方法原型,没有方法体
    • native:用来集成java代码和其他语言的代码
    • synchronized:用来控制多个并发线程对共享数据的访问

    跟 C++ 不同,Java 中类的成员方法不可以在类外部定义,且类中的所有成员方法都是相互可见的,跟定义顺序无关。

    变长参数

    有时需要方法接受未知个数的变量,这时可用变长参数(类型名后加3个点),然后在方法体中用增强的 for 循环遍历:

    public void fun(int... arr) {
    	for (int i : arr) {
    		System.out.println(i);
    	}
    }
    

    Java 中没有命名空间,但是通过包实现了类似的效果。

    • 包名不可重复,一般用小写,用域名的反序做前缀
    • 一个 Java 源文件就是一个编译单元,其中只能有一个public类,且该文件必须与该类同名,可以有多个非public类。编译后每个类都对应一个单独的字节码文件(即使是非public类)。
    • 如果类定义在某个包中,那么 package 语句应该在源文件的首行。如果源文件包含import语句,那么应该放在package语句之后,类定义之前。
    • import语句和package语句对源文件中定义的所有类都有效。
    • 包名一定对应目录名,但目录名不一定对应包名。
    • 引入包时,可以使用通配符,例如 import java.io.*;
    • Java 编译器自动为所有程序自动引入 java.lang

    类和成员的访问权限控制

    类:要访问不同包中的类,该类必须是 public 的。

    成员:

    • public:可被任何其他方法访问
    • default:仅允许来自同一个包的访问
    • protected:只可被同一个类及其子类访问
    • private:只可被同一个类访问
    - public protect default private
    任何类 × × ×
    不同包中的非子类 × × ×
    不同包中的子类 × ×
    同一个包中的非子类 ×
    同一个包中的子类 ×
    同一个类

    一般将属性设置为私有,通过共有的接口访问:

    public class People {
    	private int age;
    	public void setAge(int age) {
    		this.age = age;
    	}
    	public int getAge() {
    		return this.age;
    	}
    }
    

    内存回收 GC

    当对象离开作用域,或者没有引用指向对象时,Java 的垃圾回收机制会回收这个对象所占用的资源。

    Java 的垃圾回收器周期性运行,回收对象前,会自动调用对象的 finalize() 方法(该方法来自 Object 对象)。

    枚举类型和枚举类

    枚举类就是一个类,可以有成员方法和成员属性,隐含继承自 java.lang.Enum,不能再继承其他类。

    对象的可取值有一定范围,且可以一一列出来,就可以用枚举类,例如一周的七天等:

    [public] enum 枚举类型名称 [implements 接口名称列表] {
    枚举值;
    成员变量;
    成员方法;
    }

    enum Score {
    	GOOD,
    	BAD;
    };
    public class ScoreTest {
    	public static void main(String[] args) {
    		giveScore(Score.GOOD);
    	}
    	public static void giveScore(Score s) {
    		switch(s) {
    			case GOOD: System.out.println("Good"); break;
    			case BAD: System.out.println("Bad"); break;
    		}
    	}
    }
    

    枚举类型的默认方法:

    • values():静态方法,用于获取枚举类型的枚举值数组
    • toString():返回枚举值的字符串
    • valueOf():将字符串形式的枚举值转为枚举类型对象
    • Ordinal():获得对象在枚举类型中的位置索引
    enum Player {
    	YAOMING(240, 110),
    	DA(200, 95);		// 枚举类中的枚举值自动调用构造函数初始化
    
    	private final int height;
    	private final int weight;
    	Player(int height, int weight) {
    		this.height = height;
    		this.weight = weight;
    	}
    	public int getHeight() {
    	    return this.height;
    	}
    }
    public class PlayerTest {
    	public static void main(String[] args) {
    		for (Player p : Player.values()) { // 现在有两个枚举对象
    			System.out.println(p.getHeight());
    		}
    	}
    }
    

    输出:

    240
    200
    

    类的重用

    继承

    Java 语言只支持单继承。

    子类继承父类之后,得到父类所有的成员属性和方法。子类可以新增属性和方法,也可以覆盖父类的属性和方法。

    注意:父类的 private 私有属性和方法,子类是无法直接访问的。

    public class People {
    	int age;
    	String say(String s) {
    		System.out.println(s);
    	}
    }
    public class Teacher extends People {
    	int grade;
    	String teach(String s) {
    		System.out.println("teach to student:" + s);
    	}
    }
    

    隐藏和覆盖

    属性的隐藏

    子类中声明了与父类中同名的成员变量时,从父类继承过来的成员变量就会被隐藏,此时子类有两个同名的变量(从父类继承的和自己声明的)。

    当子类执行继承自父类的操作时,处理的是继承自父类的变量。当子类执行自己声明的方法时,操作的是自己声明的变量。

    class A {
    	int aMember;
    	static int x = 2; // 静态成员不会被继承,但可以被所有子类对象访问
    }
    class B extends A {
    	String aMember;
    	int fun() {
    		return super.aMember; // 显式的使用父类的成员变量
    	}
    }
    

    例如:

    class A {
        int x = 1;
        static int y = 2;
        void setY(int y) {
            this.y = y;
        }
    }
    class B extends A {
        int x = 90;
        int y = 91;
        void fun() {
            System.out.println("super.x is:" + super.x + ", x is:" + x);
            System.out.println("super.y is:" + super.y + ", y is:" + y);
        }
    }
    public class H {
        public static void main(String[] args) {
            B b = new B();
            b.fun();
            b.setY(666);
            b.fun();
        }
    }
    

    输出:

    super.x is:1, x is:90
    super.y is:2, y is:91
    super.x is:1, x is:90
    super.y is:666, y is:91
    

    方法的覆盖

    • 子类要覆盖父类的方法时,覆盖方法的返回类型、方法名、参数的个数和类型都必须和被覆盖的方法一样。
    • 调用时,通过不同的类名或方法名区分使用的是哪个方法。
    • 覆盖方法的访问权限可以比被覆盖的更宽松,但不能更严格。
    • 基类中声明为 final 和 static 的方法不可覆盖,基类中的抽象方法必须覆盖

    Object 类

    Object 类的主要方法:

    • public final Class getClass():获取当前对象所属类的信息
    • public String toString():返回表示当前对象的字符串
    • public boolean equals(Object obj):判断两个对象的引用是否指向同一个对象(相当于 ==),是则返回 true,否则返回 false
    • protected Object clone():复制当前对象并返回副本
    • public int hashCode():返回该对象的哈希值
    • protected void finalize() throws Throwable:在对象回收时执行,回收资源

    对象的相等和同一

    相等的对象未必是同一个,同一个对象一定相等。

    比较运算符 == 判断的是两个对象是否的同一个,跟 Object 对象的 equals 方法一样。如果需要判断对象是否相等,需要覆盖 equals 方法。

    class A {
    	int age;
    }
    public class B {
    	public static void main(String[] args) {
    		A a1 = new A();
    		A a2 = new A();
    		System.out.println(a1 == a2 ? "a1 == a2" : "a1 != a2");
    		System.out.println(a1.equals(a2) ? "a1 equals a2" : "a1 not equals a2");
    	}
    }
    

    输出:

    a1 != a2
    a1 not equals a2
    

    final 类与 final 方法

    终结类不可被继承,终结方法不能被子类覆盖。否则编译报错。

    final class {
    	public final String fun() { return "hello";}
    	//...
    }
    

    abstract 类

    • 抽象类中,至少要有一个抽象方法
    • 只要有抽象方法,这个类就必须声明为抽象类
    • 抽象类不可实例化,只能做父类
    • 接口是纯抽象类,接口中的所有方法都是抽象方法
    abstract class abs {
    	public abstract int fun();
    }
    public class Test {
    	public static void main(String[] args) {
    	    Test t = new Test();
    		System.out.println(t.fun());
    	}
    	public int fun() {
    		return 666;
    	}
    }
    

    泛型

    Java 跟 C++ 一样,都是强类型语言。当我们需要写一个可以用于多种数据类型的方法时,就需要用到泛型。

    泛型,就是将变量的类型也作为变量。调用具体的泛型方法时,需同时指定类型。

    • 泛型类的类型参数声明部分在类名之前(例如 public <T> classA {...}
    • 泛型方法的类型参数声明部分在方法返回类型之前(例如public static <T1, T2> void fun() {...})。
    • 类型参数声明部分可以包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
    • 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
    • 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型(例如 Number、String 等),不能是原始类型(int、double、char 等)。

    泛型接口

    定义泛型接口时,在接口名之后放类型参数声明,类型声明可以在接口内部的任何地方使用:

    public interface General<T> {
    	public T fun();
    }
    

    类在实现泛型接口时,需要指定泛型的具体类型,可以是自定义的对象类型:

    public class NumGeneral implements General<Number> {
    	public Number fun() {
    		return 666;
    	}
    	public static void main(String[] args) {
    	    NumGeneral ng = new NumGeneral();
    	    System.out.println(ng.fun());
    	}
    }
    

    泛型类

    跟泛型接口类似,泛型类的类型声明放在类名后面。泛型类的类型声明可以在类内部的任何地方使用:

    class A <T> {
    	private T data;
    	public A(T data) {
    		this.data = data;
    	}
    	public T getData() {
    		return data;
    	}
    }
    public class Test {
    	public static void main(String[] args) {
    		A a = new A<Number>(666);		// 这里如果不加 <Number>指定类型,执行时会有提示
    		System.out.println(a.getData());
    		A a2 = new A<String>("hello world");
    		System.out.println(a2.getData());
    	}
    }
    

    泛型方法

    如果只是想写一个可以处理多种数据类型的方法,也是可以的,在返回值之前用尖括号声明(例如 public static <T> void fun())后,就可在方法的参数、返回值、方法体中使用泛型:

    public class Test {
    	public static void main(String[] args) {
    	    System.out.println(returnT("hello"));
    	    System.out.println(returnT(666));
    	    printT("hello");
    	    printT(666);
    	}
    	public static <T> T returnT(T data) {
    	    return data;
    	}
    	public static <T> void printT(T data) {
    	    System.out.println(data);
    	}
    }
    

    限定泛型的类型

    在用尖括号声明泛型的类型时,可以对其加以限定,具体语法为 <T extends >

    public class Test {
    	public static void main(String[] args) {
    	    System.out.println(returnT("hello")); // 会报错:<T>returnT(T) in Test cannot be applied to (java.lang.String)
    	    System.out.println(returnT(666));
    	    printT("hello");
    	    printT(666);
    	}
    	// 类型限定为 Number
    	public static <T extends Number> T returnT(T data) {
    	    return data;
    	}
    	// 类型限定为实现了 Comparable 接口的
    	public static <T extends Comparable<T>> void printT(T data) {
    	    System.out.println(data);
    	}
    }
    

    类型通配符

    1、类型通配符一般是使用?代替具体的类型参数。例如 List<?> 在逻辑上是List<String>List<Number> 等所有 List<具体类型实参> 的父类。
    2、类型通配符上限通过 List<? extends 具体类型> 来定义,例如 List<? extends Number> 表示通配符泛型值接受 Number 及其下层子类类型。
    3、类型通配符下限通过 List<? super 具体类型> 来定义,例如 List<? super Number> 表示类型只能接受Number及其父类类型,如Objec类型的实例。

  • 相关阅读:
    活动的生命周期
    活动
    开始编程前的准备工作
    数组转List
    Word根据模板生成数据
    Excel根据模板生成数据
    php取年份区间
    世界 国家 省份 sql
    相册处理,php中获取一组前缀相同的元素值
    mysql添加字段
  • 原文地址:https://www.cnblogs.com/kika/p/10851527.html
Copyright © 2011-2022 走看看