项目1 权限修饰符
概述
在Java中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限,
- public:公共的。
- protected:受保护的
- default:默认的
- private:私有的
不同权限的访问能力
public | protected | default(空的) | private | |
---|---|---|---|---|
同一类中 | √ | √ | √ | √ |
同一包中(子类与无关类) | √ | √ | √ | |
不同包的子类 | √ | √ | ||
不同包中的无关类 | √ |
可见,public具有最大权限。private则是最小权限。
编写代码时,如果没有特殊的考虑,建议这样使用权限:
- 成员变量使用
private
,隐藏细节。 - 构造方法使用
public
,方便创建对象。 - 成员方法使用
public
,方便调用方法。
小贴士:不加权限修饰符,其访问能力与default修饰符相同
示例代码
public class Demo01 {
private int aa = 1; // 私有的
int bb = 2; // 默认的
protected int cc = 3; // 受保护的
public int dd = 4; // 公共的
public void test1(){ // 本类中访问,都可以
System.out.println(aa);
System.out.println(bb);
System.out.println(cc);
System.out.println(dd);
}
}
public class Demo02 extends Demo01 { // 同包子类
public void test(){
//System.out.println(aa); // 不能访问私有的
System.out.println(bb);
System.out.println(cc);
System.out.println(dd);
}
}
public class Demo03 extends Demo01{ // 不同包子类
public void test(){
//System.out.println(aa);
//System.out.println(bb); // 不同包中,default的也不能访问
System.out.println(cc);
System.out.println(dd);
}
}
public class Demo04 { // 不同包类
public static void main(String[] args) {
Demo01 demo = new Demo01();
//System.out.println(demo.aa);
//System.out.println(demo.bb);
//System.out.println(demo.cc);
System.out.println(demo.dd);
}
}
项目2 包
基本用法
例如:package com.offcn.test 系统自动建立三个文件夹,结构如下:
com
offcn
test
该文件中所定义的类都在test文件夹下。
示例代码
package com.offcn.finaltest;
JDK中的包
1、java.lang包含一些Java语言的核心类,如String、Math、Integer 、System和Thread,提供常用功能。
2、java.util包含一些实用工具类,如集合、日期等。
3、java.io 包含能提供多种输入/输出功能的类。
4、java.net包含执行与网络相关的操作的类。
5、java.awt包含构成抽象窗口工具集的多个类,这些类用来创建和管理应用程序的图形用户界面(GUI)。
import的多导入
import com.offcn.*;引入该包下所有类。
使用import语句应该注意的几点:
1、import语句定义在package语句后
2、java.lang包是默认被导入的,该包下所有类都可以直接使用。
3、包的导入不是迭代的,也就是当使用com.offcn.*时只会导入该包下的所有类,如果该包下有文件夹a,则a下的所有类不会被导入。
4、同一个包下的类,不需要导入。
项目3多态
泛化
泛化就是抽象化,把具体的事物当作抽象的东西看待(把猫看成动物)。
泛化也叫向上转型,是通往多态的路口。
以用同样的类型处理不同的东西。
注意:只有向上转型,没有向下转型。向下转型叫做强转,这样做很不安全!
Cat c = (Cat)o; 编译可以通过,但是运行时会出现错误。
泛化指的是引用的泛化,不是对象的泛化,内存中的对象还是原来的对象,只是把引用的类型给改变了
多态的概念
简单来说,多态就是一个事物的多种状态(形态)。
比方说按下 F1 键这个动作,如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的就是Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。
多态的分类
Java中的多态,可以分为静态多态和动态多态。
静态多态就是指方法的重载。
动态多态是指“动态绑定”。而我们这里所说的多态,大多数是指动态多态。
多态应该具备的条件
- 继承
- 子类重写父类的方法
- 父类引用指向子类对象(泛化)
动态绑定和静态绑定
所谓动态绑定,是指在编译期不能确定引用指向什么类型,而是在运行期选择具体的类型。
double ran = Math.random();
Animal a;
if(ran>0.5){
a = new Cat();
}else{
a = new Dog();
}
a.eat();
多态中成员方法的访问特点:编译看左边,运行看右边
静态绑定
静态绑定是指编译期就确定调用的是父类中的成员。
动态绑定只是针对类中的普通方法,而对于成员变量,静态变量,静态方法,采用的是静态绑定。也就是说,对于成员变量,静态变量,和静态方法,绑定的是声明时类型中的成员。
Animal a = new Cat();
a.eat(); //动态绑定
System.out.println(a.name); //静态绑定
a.sayHello(); // 静态绑定
总结:成员变量、静态方法、静态变量、私有变量等采用静态绑定
编译看左边,运行看左边
项目4 引用类型转换
多态的转型分为向上转型与向下转型两种:
向上转型
- 向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。
当父类引用指向一个子类对象时,便是向上转型。
使用格式:
父类类型 变量名 = new 子类类型();
如:Animal a = new Cat();
向下转型
- 向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。
一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。
使用格式:
子类类型 变量名 = (子类类型) 父类变量名;
如:Cat c =(Cat) a;
为什么要转型
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型。
转换前,我们最好先做一个判断
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void catchMouse() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void watchHouse() {
System.out.println("看家");
}
}
____________________________________________
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
if (a instanceof Cat){
Cat c = (Cat)a;
c.catchMouse(); // 调用的是 Cat 的 catchMouse
} else if (a instanceof Dog){
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse
}
}
}
项目5 多态的好处及应用
好处
站在更高的层次管理对象的行为
例如:气象专家告诉农民收割庄稼。
多态的应用
1.2多态的应用
案例1: 多态做为形参(接受范围更广的对象,避免方法重载过度使用)
需求:完成喂动物操作。定义一个动物园类,类中有一个喂动物的方法。
动物包括:老虎,猴子,狗,猫。每个动物类中都有一个eat的方法。(喂动物即是调用动物的eat方法)
示例代码
public class Animal {
public void eat(){
System.out.println("吃");
}
}
public class Tiger extends Animal{
public void eat(){
System.out.println("吃肉###");
}
}
public class Monkey extends Animal{
public void eat(){
System.out.println("吃桃...");
}
}
public class Cat extends Animal{
public void eat(){
System.out.println("吃鱼");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("啃骨头");
}
}
public class Zoo {
public void feed(Animal a){
a.eat();
}
/*
public void feed(Tiger tiger){
tiger.eat();
}
public void feed(Monkey monkey){
monkey.eat();
}
public void feed(Cat cat){
cat.eat();
}
public void feed(Dog dog){
dog.eat();
}
*/
}
public static void main(String[] args) {
Zoo zoo = new Zoo();
Tiger tiger = new Tiger();
zoo.feed(tiger);
Monkey monkey = new Monkey();
zoo.feed(monkey);
Cat cat = new Cat();
zoo.feed(cat);
Dog dog = new Dog();
zoo.feed(dog);
}
案例2: 多态做为返回值类型(简单工厂模式)
需求:有一个生产汽车的工厂,有一个生产汽车的方法,根据客户不同的需求,可以生产出不同的汽车。汽车包括:奔驰(benz)、宝马(BMW)、法拉利(ferrari)
示例代码
public class Car {
public void run(){
System.out.println("run");
}
}
public class CarFactory {
public Car makeCar(String name){
if("bmw".equals(name)){
return new BMW();
}
if("benz".equals(name)){
return new Benz();
}
if("ferrari".equals(name)){
return new Ferrari();
}
return null;
}
/*
public BMW makeBMW(){
return new BMW();
}
public Benz makeBenz(){
return new Benz();
}
public Ferrari makeFerrari(){
return new Ferrari();
}
*/
}
public class BMW extends Car{
public void run(){
System.out.println("宝马在路上飞驰...");
}
}
public class Benz extends Car{
public void run(){
System.out.println("奔驰在路上奔驰###");
}
}
public class Ferrari extends Car{
public void run(){
System.out.println("法拉利跑的很快");
}
}
项目6 抽象类
抽象方法
用abstract关键字修饰的方法,称为抽象方法。
抽象方法的特点:只有方法的声明,没有方法体。
抽象方法的作用:被子类重写,为子类规定了方法的调用格式,具体的操作内容等待子类去完成。
生活中的例子:简历模板。
示例代码
public abstract void show();
抽象方法存在的类必须是一个抽象类
抽象类
特点:
1、 抽象类不能被实例化。抽象类的唯一用途就是被子类继承。
2、继承抽象类的类,有责任去实现抽象类中的所有抽象方法。如果不实现,那么子类也必须声明为抽象类。
抽象类中可以包含非抽象方法
public abstract class Person {
public abstract void eat();
public void testMethod(){
//非抽象方法
System.out.println("抽象类中可以存在非抽象方法");
}
}
抽象类的其他细节
1、抽象类不能创建对象,那么抽象类中是否有构造方法?
抽象类中一定有构造方法。主要为了初始化抽象类中的属性。通常由子类实现。
public abstract class Vehicle { // 抽象类 至少包含一个抽象方法的类
public Vehicle(){
System.out.println("抽象类的构造方法");
}
public abstract void run(); // 抽象方法——只有方法声明,没有方法体
}
2、final和abstract是否可以同时修饰一个类?
一定不能同时修饰。因为:抽象类的作用就是被继承,而final修饰的类不能被继承。
总结:
-
抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
-
抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
-
抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。