一、包的基本认识
包是组织类的一种方式,使用包的主要目的是保证类的唯一性。
导入包中的类
我们可以使用import语句导入包,也可以导入具体的类名,但我们更建议导入具体的类名,因为有的类在不同包中有相同的名字,必须写完整防止出现冲突。
import java.util.*;
import java.sql.*;
public class Test {
public static void main(String[] args) {
// util 和 sql 中都存在一个 Date 这样的类, 此时就会出现歧义, 编译出错
Date date = new Date();
System.out.println(date.getTime());
}
}
// 编译出错
Error:(5, 9) java: 对Date的引用不明确
java.sql 中的类 java.sql.Date 和 java.util 中的类 java.util.Date 都匹配
import java.util.*;
import java.sql.*;
public class Test {
public static void main(String[] args) {
java.util.Date date = new java.util.Date();//使用具体的类名
System.out.println(date.getTime());
}
}
使用import static导入静态类
import static可以直接导入包的静态类和静态方法
import static java.lang.System.*;//导入静态类
public class Test {
public static void main(String[] args) {
out.println("hello");
}
}
包的权限访问控制
类的修饰符有public、private等,public和private中的成员,只能被类的内部使用,如果我们在类的前面不加public和private修饰符,就可以在同一个包中的其他类中使用,但是不能被其他包中的类所使用。下面我们来举例分析:
首先我们在src底下创建了一个包,包中存放了两个类,一个Demo1类一个Demo2类,可以发现Demo1和Demo2在同一个包中,而Main类不在此包中,接下来我们写一个简单的代码
package com.bit.demo1;
public class Demo1 {
int value = 10;
}
package com.bit.demo1;
public class Demo2 extends Demo1{
public static void main(String[] args) {
Demo1 demo = new Demo1();
System.out.println(demo.value);
}
}
当我们使用extends关键字使Demo2中的类继承Demo1中的类后,打印出来的结果是正确的并且编译无误:
但当我们在不同包中的Main类使用extends关键字继承Demo1类就会报错:
import com.bit.demo1.Demo1;
public class Main {
public static void main(String[] args) {
Demo1 demo = new Demo1();
System.out.println(demo.value);
}
}
二、继承
继承的基本概念以及理解
代码中我们经常会写到一一些功能相同或者大部分重复的代码,在c语言中我们一般使用函数将其抽象出来,而在java中我们使用类将其抽象出来,在一些有共性的事物中我们抽出其相同的本质并写成类。
比如说鸟、猫、狗都是动物,我们可以将其动物的本质抽离出来写一个动物类,这样我们以后在创建新的动物时可以直接【继承】动物类。
class Animal{
public String name;
public Animal(String name){
this.name = name;
}
public void eat(String food){
System.out.println(this.name+"正在吃"+food);
}
}
在动物类中,每一个以后继承此类的动物都有一个名字,有一个eat方法。
class Cat extends Animal{
public Cat(String name) {
super(name);//super可以直接指代当前对象中在父类中的特征,并不包含在子类对象中
}
}
如果我们在继承之后没有书写任何子类方法,系统会自动使用父类的方法
class Dog extends Animal{
public Dog(String name){
super(name);
}
}
class Bird extends Animal{
public Bird(String name){
super(name);
}
public void fly(){ //在鸟类中我们加入了一个新的子类方法
System.out.println(this.name+"正在飞");
}
}
我们在书写新类的时候,只需要new一个新的子类对象即可调用父类的方法
public class Test {
public static void main(String[] args) {
Cat cat = new Cat("小黑");
cat.eat("猫粮");
Bird bird = new Bird("圆圆");
bird.fly();
}
}
值得注意的是,父类的方法访问也是有限制的,如果我们将上例中name的修饰从public改成private,则我们不能在子类中访问此方法。
使用public的访问范围太大,使用private的访问范围太小,所以为了更好的封装方法,我们选择使用protected修饰方法,这样只有该父类的子类和同一个包中的其他类可以访问。
小结: Java 中对于字段和方法共有四种访问权限 private: 类内部能访问, 类外部不能访问 默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问. protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问. public : 类内部和类的调用者都能访问
但是继承一般不会超过三层,如果超出三层会造成代码的冗余,为了对语法上进行限制继承,我们可以使用final关键字
final关键字
final关键字修饰的类表示不能被继承
final public class Animal {
...
}
public class Bird extends Animal {
...
}
// 编译出错
Error:(3, 27) java: 无法从最终com.bit.Animal进行继承
三、组合
组合也是一种表示类之间关系的表达方式
组合并没有涉及到特殊的语法(诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段
public class Student {
...
}
public class Teacher {
...
}
public class School {
public Student[] students;
public Teacher[] teachers;
}
组合表示has a 关系
在刚才的例子中, 我们可以理解成一个学校中 "包含" 若干学生和教师
继承表示 is a关系
在上面的 "动物和猫" 的例子中, 我们可以理解成一只猫也 "是" 一种动物.