今天继续Java系列,上篇写到了java面向对象的三大特征,今天看下面向对象中的关键字。
package
package称为包,用于指明该文件中定义的类、接口等结构所在的包。
如何使用
格式如下:
package 顶层包名.子包名 ;
示例:pack1\pack2\PackageTest.java
package pack1.pack2; //指定类PackageTest属于包pack1.pack2
public class PackageTest{
public void display(){
System.out.println("helllo");
}
}
注:
- 一个源文件只能有一个声明包的package语句
- package语句作为java源文件的第一条语句出现,若缺省该语句,则指定为无名包
- 包名属于标识符,满足标识符命名的规则和规范(全部小写)、见名知意,包通常使用所在公司域名的倒置,另外取包名时不要使用
java.xxx
- 包对应于文件系统的目录,package语句中用
.
来指明包的层次,每.
一次就表示一层文件目录 - 同一个包下可以声明多个结构(类、接口),但是不能定义同名的结构(类、接口),不同的包下可以定义同名的结构(类、接口)
应用示例
包可以包含类和子包,划分项目层次,便于管理。包可以帮助管理大型软件系统,将功能相近的类划分到同一个包中,比如MVC的设计模式。包有效的解决了类命名冲突的问题。包还可以控制访问权限。
示例:MVC设计模式。
MVC是一种软件构建模式,目的是为了降低程序开发中代码业务的耦合度。
MVC设计模式将整个程序分为三个层次:视图模型层(viewer)、控制器层(controller)与数据模型层(model)。这种将程序输入输出、数据处理、以及数据的展示分离开来的设计模式使程序结构变的灵活而且清晰,同时也描述了程序各个对象间的通信方式,降低了程序的耦合性。
视图层viewer:显示数据,为用户提供使用界面,与用户直接进行交互。
- 相关工具类:view.utils
- 自定义view:view.ui
控制层controller:解析用户请求,处理业务逻辑,给予用户响应。
- 应用界面相关:controller.activity
- 存放fragment:controller.fragment
- 显示列表的适配器:controller.adapter
- 服务相关的:controller.service
- 抽取的基类:controller.base
模型层model:主要承载数据、处理数据。
- 数据对象封装:model.bean/domain
- 数据库操作类:model.dao
- 数据库:model.db
JDK中主要包的介绍:
- java.lang:包含一些java语言的核心类,如String、Math、Integer、System和Thread,提供常用功能
- java.net:包含执行与网络相关的操作的类和接口
- java.io:包含能提供多种输入输出功能的类
- java.util:包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数
- java.text:包含了一些java格式化相关的类
- java.sql:包含了java进行JDBC数据库编程的相关类/接口
- java.awt:包含了构成抽象窗口工具集的多个类,这些类被用来构建和管理应用程序的图形用户界面
import
为了使用定义在其它包中的java类,需要用import语句来显式引入指定包下所需要的类,相当于import语句告诉编译器到哪里去寻找这个类。
如何使用
格式如下:
import 包名.类名
注:
- import语句声明在包的声明和类的声明之间
- 如果需要导入多个类或接口,那么就并列多个import语句即可
- 如果使用
a.*
导入结构,表示可以导入a包下的所有结构 - 如果导入的类或接口是java.lang包下的,或者是当前包下的,则可以省略此import语句
- 如果已经导入java.a包下的类,那么如果需要使用a包的子包下的类的话,仍需导入
- 如果在代码中使用不同包下的同名类,那么需要使用类的全类名的方式指明调用的是哪个类
import static
组合的使用:调用指定类或接口下的静态的属性或方法
应用示例
示例:
import pack1.pack2.Test; //import pack1.pack2.* 表示引入pack1.pack2包中的所有结构
public class PackTest{
public static void main(String args[]){
Test t = new Test(); //Test类在pack1.pack2包中定义
t.display();
}
}
this
在java中this关键字不算难理解,它的作用和其词义很接近。this在方法(准确点应该是实例方法或非static的方法)内部使用,表示调用该方法的对象。this也可以在构造器内部使用,表示该构造器正在初始化的对象。
如何使用
this可以调用的结构有:成员变量、方法和构造器。
在实例方法或构造器中,如果使用当前类的成员变量或成员方法可以在其前面添加this,增强程序的可读性,不过通常都习惯省略this。但是当形参与成员变量同名时,如果在方法内或构造器内需要使用成员变量,必须添加this来表明该变量是类的成员变量。即可以用this来区分成员变量和局部变量。
this可以作为一个类中构造器相互调用的特殊格式,this()调用本类的无参构造器,this(实参列表)调用本类的有参构造器。
应用示例
实例方法或构造器中使用当前对象成员的示例:
public class Rectangle {
int length;
int width;
public int area() {
return this.length * this.width;
}
public int perimeter(){
return 2 * (this.length + this.width);
}
public void print(char sign) {
for (int i = 1; i <= this.width; i++) {
for (int j = 1; j <= this.length; j++) {
System.out.print(sign);
}
System.out.println();
}
}
public String getInfo(){
return "长:" + this.length + ",宽:" + this.width +",面积:" + this.area() +",周长:" + this.perimeter();
}
}
注:使用this访问属性和方法时,如果在本类中未找到,会从父类中查找。
同一个类中构造器相互调用示例:
public class Student {
private String name;
private int age;
//无参构造
public Student() {
//this("",18); //调用本类有参构造器
}
//有参构造
public Student(String name) {
this(); //调用本类无参构造器
this.name = name;
}
//有参构造
public Student(String name,int age){
this(name); //调用本类中有一个String参数的构造器
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getInfo(){
return "姓名:" + name +",年龄:" + age;
}
}
注:不能出现递归调用,比如调用自身构造器,如果一个类中声明了n个构造器,则最多有n-1个构造器中使用了this(形参列表)。this()和this(实参列表)只能声明在构造器首行,在类的一个构造器中,最多只能声明一个this(参数列表)。
super
super用于Java的类中,实现调用父类中的指定操作。
如何使用
super可用于访问父类中定义的属性、可用于调用父类中定义的成员方法、可用于在子类构造器中调用父类的构造器。
- 子类中调用父类被重写的方法。
- 如果子类没有重写父类的方法,只要权限修饰符允许,在子类中完全可以直接调用父类的方法
- 如果子类重写了父类的方法,在子类中需要通过super.才能调用父类被重写的方法,否则默认调用的子类重写的方法
- 子类中调用父类中同名的成员变量。
- 如果实例变量与局部变量重名,可以在实例变量前面加this.进行区别
- 如果子类实例变量和父类实例变量重名,并且父类的该实例变量在子类仍然可见,在子类中要访问父类声明的实例变量需要在父类实例变量前加super,否则默认访问的是子类自己声明的实例变量
- 如果父子类实例变量没有重名,只要权限修饰符允许,在子类中完全可以直接访问父类中声明的实例变量,也可以用this.实例访问,也可以用super.实例变量访问
- 子类构造器中调用父类构造器。
- 子类继承父类时,不会继承父类的构造器,只能通过super(形参列表)的方式调用父类指定的构造器
- 规定super(形参列表)必须声明在构造器的首行
- 在构造器的首行,this(形参列表)和super(形参列表)只能二选一
- 如果在子类构造器的首行既没有显示调用this(形参列表),也没有super(形参列表),则子类此构造器默认调用super(),即调用父类中空参的构造器
- 子类的任何一个构造器中,要么会调用本类中重载的构造器,要么会调用父类的构造器,只能是这两种情况之一
- 一个类中声明有n个构造器,最多有n-1个构造器中使用了this(形参列表),则剩下的那个一定使用super(形参列表)
注:当父类出现同名成员时,可以用super表明调用的是父类中的成员。super的追溯不仅限于直接父类。super和this的用法相像,this代表本类对象的引用,super代表父类的内存空间的标识。
应用示例
子类中调用父类被重写的方法示例:
public class Phone {
public void sendMessage(){
System.out.println("发短信");
}
public void call(){
System.out.println("打电话");
}
public void showNum(){
System.out.println("来电显示号码");
}
}
public class SmartPhone extends Phone{
//重写父类的来电显示功能的方法
public void showNum(){
//来电显示姓名和图片功能
System.out.println("显示来电姓名");
System.out.println("显示头像");
//保留父类来电显示号码的功能
super.showNum(); //此处必须加super.,否则就是无限递归,那么就会栈内存溢出
}
}
总结:
- 方法前面没有super.和this.:先从子类找匹配方法,如果没有再从直接父类找,再没有继续往上追溯
- 方法前面由this.:先从子类找匹配方法,如果没有再从直接父类找,再没有继续往上追溯
- 方法前面由super.:从当前子类的直接父类找,如果没有继续往上追溯
子类中调用父类中同名的成员变量示例:
class Father{
int a = 10;
int b = 11;
}
class Son extends Father{
int a = 20;
public void test(){
//子类与父类的属性同名,子类对象中就有两个a
System.out.println("子类的a:" + a); //20先局部变量找,没有再找本类成员变量
System.out.println("子类的a:" + this.a); //20先从本类成员变量找
System.out.println("父类的a:" + super.a); //10直接从父类成员变量找
//子类与父类的属性不同名,是同一个b
System.out.println("b = " + b); //11先找局部变量找,没有再找本类成员变量,没有再从父类找
System.out.println("b = " + this.b); //11先从本类成员变量找,没有再从父类找
System.out.println("b = " + super.b); //11直接从父类局部变量找
}
public void method(int a, int b){
//子类与父类的属性同名,子类对象中就有两个成员变量a,此时方法中还有一个局部变量a
System.out.println("局部变量的a:" + a); //30先找局部变量
System.out.println("子类的a:" + this.a); //20先从本类成员变量找
System.out.println("父类的a:" + super.a); //10直接从父类成员变量找
System.out.println("b = " + b); //13先找局部变量
System.out.println("b = " + this.b); //11先从本类成员变量找
System.out.println("b = " + super.b); //11直接从父类局部变量找
}
}
class Test{
public static void main(String[] args){
Son son = new Son();
son.test();
son.method(30,13);
}
}
总结:
- 变量前面没有super.和this.:在构造器、代码块、方法中如果出现使用某个变量,先查看是否是当前块声明的局部变量,如果不是局部变量,先从当前执行代码的本类去找成员变量。如果从当前执行代码的本类中没有找到,会往上找父类声明的成员变量(权限修饰符允许在子类中访问的)
- 变量前面有this.:通过this找成员变量时,先从当前执行代码的本类去找成员变量,如果从当前执行代码的本类中没有找到,会往上找父类声明的成员变量(权限修饰符允许在子类中访问的)
- 变量前面有super.:通过super找成员变量,直接从当前执行代码的直接父类去找成员变量(权限修饰符允许在子类中访问的),如果直接父类没有,就去父类的父类中找(权限修饰符允许在子类中访问的)
注:应该避免子类声明和父类重名的成员变量。
子类构造器中调用父类构造器示例:
class A{
A(){
System.out.println("A类无参构造器");
}
A(int a){
System.out.println("A类有参构造器");
}
}
class B extends A{
B(){
super(); //可以省略,调用父类的无参构造
System.out.println("B类无参构造器");
}
B(int a){
super(a); //调用父类有参构造
System.out.println("B类有参构造器");
}
}
class Test8{
public static void main(String[] args){
B b1 = new B();
B b2 = new B(10);
}
}
this和super:
this:当前对象
- 在构造器和非静态代码块中,表示正在new的对象
- 在实例方法中,表示调用当前方法的对象
- this.成员变量:表示当前对象的某个成员变量,而不是局部变量
- this.成员方法:表示当前对象的某个成员方法,完全可以省略this.
- this()或this(实参列表):调用另一个构造器协助当前对象的实例化,只能在构造器首行,只会找本类的构造器,找不到就报错
super:引用父类声明的成员
- super.成员变量:表示当前对象的某个成员变量,该成员变量在父类中声明的
- super.成员方法:表示当前对象的某个成员方法,该成员变量在父类中声明的
- super()或super(实参列表):调用父类的构造器协助当前对象的实例化,只能在构造器首行,只会找直接父类的对应构造器,找不到就报错
static
当编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字参会产出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用,但有时希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间中只有一份,即想让一个成员变量被类的所有实例所共享,就用static修饰即可,称为类变量(或类属性)。
此外在类中声明的实例方法,在类的外面必须先创建对象才能调用,但是有些方法的调用者和当前类的对象无关,这样的方法通常被声明为类方法。这里的类变量、类方法,只需要使用static修饰即可,故也称为静态变量、静态方法。
如何使用
static的使用范围:在java类中,可用static修饰属性、方法、代码块、内部类。
被修饰后的成员具备的特点:随着类的加载而加载,优先于对象存在,修饰的成员被所有对象所共享,访问权限允许时可不创建对象直接被类调用。
静态变量:
语法格式:使用static修饰的成员变量就是静态变量。
[修饰符] class 类{
[其他修饰符] static 数据类型 变量名;
}
特点:
- 静态变量的默认值规则和实例变量一样
- 静态变量值是所有对象共享
- 静态变量在本类中,可以在任意方法、代码块、构造器中直接使用
- 如果权限修饰符允许,在其他类中可以通过类名.静态变量直接访问,也可以通过对象.静态变量的方式访问(更推荐使用类名.静态变量的方式)
- 静态变量的get/set方法也是静态的,当局部变量与静态变量重名时,使用类名.静态变量进行区分
静态方法:
语法格式:用static修饰的成员方法就是静态方法。
[修饰符] class 类{
[其他修饰符] static 返回值类型 方法名(形参列表){
方法体
}
}
特点:
- 静态方法在本类的任意方法、代码块、构造器中都可以直接被调用
- 只要权限修饰符允许,静态方法在其他类中可以通过类名.静态方法的方式调用,也可以通过对象.静态方法的方式调用(但是更推荐使用类名.静态方法的方式)
- 在static方法内部只能访问类的static修饰的属性或方法,不能访问类的非static的结构
- 静态方法可以被子类继承,但不能被子类重写
- 静态方法的调用都只看编译时类型
- 因为不需要实例就可以访问static方法,因此static方法内部不能有this,也不能有super,如果有重名问题,使用类名.进行区别
应用示例
静态变量示例:
class Chinese{
String name;
int age;
static String nation;
public Chinese() {
}
public Chinese(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Chinese{" +
"name='" + name + '\'' +
", age=" + age +
", nation='" + nation + '\'' +
'}';
}
}
public class StaticTest {
public static void main(String[] args) {
Chinese c1 = new Chinese("小明",36);
c1.nation = "中华人民共和国";
Chinese c2 = new Chinese("小红",66);
System.out.println(c1);
System.out.println(c2);
System.out.println(Chinese.nation);
}
}
静态方法示例:
public class Father {
public static void method(){
System.out.println("Father.method");
}
public static void fun(){
System.out.println("Father.fun");
}
}
public class Son extends Father{
//尝试重写静态方法,加上@Override编译报错,去掉Override不报错,但是也不是重写
public static void fun(){
System.out.println("Son.fun");
}
}
public class TestStaticMethod {
public static void main(String[] args) {
Father.method();
Son.method(); //继承静态方法
Father f = new Son();
f.method(); //执行Father类中的method
}
}
final
final意为最终的不可更改的。
如何使用
final修饰类:
表示这个类不能被继承,没有子类,提高安全性,提高程序的可读性,例如String类、System类等。
final修饰方法:
表示这个方法不能被子类重写,例如Object类中的getClass()。
final修饰变量:
final修饰某个变量(成员变量或局部变量),一旦赋值它的值就不能被修改,即常量,常量名建议使用大写字母。如果某个成员变量用final修饰后没有set方法,则必须初始化。
应用示例
final修饰类示例:
final class Eunuch{
}
class Son extends Eunuch{ //错误
}
final修饰方法示例:
class Father{
public final void method(){
System.out.println("father");
}
}
class Son extends Father{
public void method(){ //错误
System.out.println("son");
}
}
final修饰成员变量示例:
public final class Test {
public static int totalNumber = 5;
public final int ID;
public Test() {
ID = ++totalNumber; //可在构造器中给final修饰的变量赋值
}
public static void main(String[] args) {
Test t = new Test();
System.out.println(t.ID);
}
}
final修饰局部变量示例:
public class TestFinal {
public static void main(String[] args){
final int MIN_SCORE ;
MIN_SCORE = 0;
final int MAX_SCORE = 100;
MAX_SCORE = 200; //非法
}
}
今天的内容就到这里,喜欢的话点个关注吧,下篇见!