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类型的实例。
Java 基础-类与面向对象的更多相关文章
- Java基础教程:面向对象编程[2]
Java基础教程:面向对象编程[2] 内容大纲 访问修饰符 四种访问修饰符 Java中,可以使用访问控制符来保护对类.变量.方法和构造方法的访问.Java 支持 4 种不同的访问权限. default ...
- Java基础教程:面向对象编程[1]
Java基础教程:面向对象编程 内容大纲 Java语言概述 Java语言特点 1.Java为纯面向对象的语言,它能够直接反映现实生活中的对象.总之,Everything is object! 2.平台 ...
- Java基础教程:面向对象编程[3]
Java基础教程:面向对象编程[3] 内容大纲 基础编程 获取用户输入 java.util.Scanner 是 Java5 的新特征,我们可以通过 Scanner 类来获取用户的输入.我们可以查看Ja ...
- Java基础语法(9)-面向对象之类的成员
title: Java基础语法(9)-面向对象之类的成员 blog: CSDN data: Java学习路线及视频 1.面向对象特征--封装 为什么需要封装?封装的作用和含义? 我要用洗衣机,只需要按 ...
- Java基础语法(11)-面向对象之关键字
title: Java基础语法(11)-面向对象之关键字 blog: CSDN data: Java学习路线及视频 1.this this是什么 它在方法内部使用,即这个方法所属对象的引用: clas ...
- JAVA基础知识之面向对象编程知识汇总
JAVA基础课程部分面向对象已经学习完成,知识结构如下: 总体知识框架: 类的结构: 面向对象编程三大特征: 关键字和抽象类接口等: 常见知识汇总: 成员变量和局部变量比较 有无返回值方法比较: 权限 ...
- Java基础语法(10)-面向对象之三大特征
title: Java基础语法(9)-面向对象之类的成员 blog: CSDN data: Java学习路线及视频 1.面向对象特征--封装 为什么需要封装?封装的作用和含义? 我要用洗衣机,只需要按 ...
- 第31节:Java基础-类与对象
前言 Java基础-类与对象,方法的重载,构造方法的重载,static关键字,main()方法,this关键字,包,访问权限,类的继承,继承性,方法的重写,super变量. 方法的重载:成员方法的重载 ...
- Java基础一:面向对象的特征
经过16年校招,自己在Java基础方面也算有了一个质的飞跃,从原来知其然,到现在知其所以然,现将学习心得总结于此. 首先需要知道类和对象是什么? 维基百科定义类为: an extensible pro ...
随机推荐
- Python numpy插入、读取至postgreSQL数据库中bytea类型字段
安装psycopg2模块,此模块用于连接PostgreSQL数据库 pip install psycopg2 # -*- coding: utf-8 -*- import psycopg2 impo ...
- 磁盘IO性能优化-实践
RAID卡缓存策略调整 原因详解 操作实例 I/O 调度算法 文件系统journal 磁盘挂载参数 操作实例 性能数据对比 RAID卡缓存策略调整 可以将RAID卡缓存策略由No Write Cach ...
- 洛谷 P2866 [USACO06NOV]糟糕的一天Bad Hair Day 牛客假日团队赛5 A (单调栈)
链接:https://ac.nowcoder.com/acm/contest/984/A 来源:牛客网 题目描述 Some of Farmer John's N cows (1 ≤ N ≤ 80,00 ...
- 2019 计蒜之道 复赛 D. “星云系统”(单调栈)
VIPKID 是在线少儿英语教育平台,网络稳定是在线教育课程质量的红线,VIPKID 为此推出了全球最稳定的教育网络系统 -- "星云系统".星云系统目前建立了覆盖全球 3535 ...
- The Preliminary Contest for ICPC Asia Xuzhou 2019 E. XKC's basketball team (线段树)
题目链接:https://nanti.jisuanke.com/t/41387 题目大意:对于给定序列,求出对于每个位置求出比该数大于m的最靠右的位置. 思路:首先对序列进行离散化,然后对于每个数的下 ...
- bzoj4383 [POI2015]Pustynia 拓扑排序+差分约束+线段树优化建图
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4383 题解 暴力的做法显然是把所有的条件拆分以后暴力建一条有向边表示小于关系. 因为不存在零环 ...
- 初始化一个React项目
1.create-react-app是一个通过npm发布的安装包,在确认Node.js和npm安装好之后,输入下面命令创建. 2.安装结束后,使用下面命令创建应用目录. 3.打开目录 4.运行项目 5 ...
- 【SaltStack官方版】—— Events&Reactor系统—BEACONS
Events&Reactor系统—BEACONS Beacons let you use the Salt event system to monitor non-Salt processes ...
- 【python】对于程序员来说,2018刑侦科推理试卷是问题么?
最近网上很火的2018刑侦科推理试卷,题目确实很考验人逻辑思维能力. 可是对于程序员来说,这根本不是问题.写个程序用穷举法计算一遍即可,太简单. import itertools class Solu ...
- JavaScript正则表达式(四)
正则表达式方法 一.test方法 用于测试字符串参数中是否存在匹配正则表达式模式的字符串 如果存在就返回true,否则返回false 实例: 1.使用test方法不设置g标志时 2.使用test方法 ...