目录
包(package)
包 (package) 是组织类的一种方式,使用包的主要目的是保证类的唯一性。也就是说,在同一个包底下,不能存在同名的类。相反,在不同的包底下,能够存在相同名字的类。那么与包有关的关键字有import与package 。
1.import关键字
我们都知道在Java中有许多现成的类放在不同的包底下提供给程序员使用。而类中有能够满足我们需求的实现方法。那么如何才能使用我们所需要的类呢?要使用import关键字来导入该类所在的包。例如:可以使用import java.util.Date 这种方式引入 java.util 这个包中的 Date 类。如果还需要使用java.util包下的其它类时,例如Scanner类,则还需要import java.util.Scanner
如果我们没有导入该包中的类,则还可以写成这种形式:java.util.Date date = new java.util.Date();
但是这种写法比较麻烦一些, 仍然建议使用 import 语句导入包。如果我们不单单只想导入java.util当中的Date类,我们也可以写成import java.util., 号代表的是通配符,顾名思义就是能够将该包下的“所有的类”都导入,为什么“所有的类”加上引号呢?这里的“所有的类”指的是我们在程序中调用了java.util包下的类时无需再导java.util.类名,而import java.util.*
这种写法能够在我们使用哪个类时就导入包中指定的哪个类,只是无需再导相同的包。但它却又不是将该包底下的所有类都导入进来。
还有特殊情况:因为在不同包底下可以有相同类名,因此如果真的遇到了**想调用不同包底下的相同的类时,两个包都要进行导入才能正常使用。**并且要看清楚编译器提示给我们的是哪个包底下的类。调用类的方法则是 类名.方法名 。
2.静态导入
使用 import static 可以导入包中的静态的方法和字段。这种情况用的比较少。例如System类中的方法println是静态方法,因此写成下面这种形式:
上面的例子看的有些别扭,但是导入静态的方法有时也会非常方便,例如:
3.package关键字
我们既然已经知道了import关键字的作用是导入一个包底下的类,而package关键字就是显示出该类是在哪个包底下的。
基本规则:
- 在文件的最上方加上一个 package 语句指定该代码在哪个包中
- 包名需要尽量指定成唯一的名字,通常会用公司的域名的颠倒形式(例如com.bit.demo1)
- 包名要和代码路径相匹配,例如创建 com.baidu.www 的包, 那么会存在一个对应的路径 com.baidu.www 来存储代码
- 如果一个类没有 package 语句, 则该类被放到一个默认包中
当我们创建了多个包时对于某一个类在哪个包底下会显得有点混乱,我们可以在该类的标签处点击鼠标右键后有如图所下的界面:
并且当创建时,编译器自动提示将该类在哪个包底下。
注意1:
util包中 有很多类,难道 “ impor java.util.*; ” 是一下子全部 都导入吗?
不是的,Java 处理的时候,需要哪个类,它才会给你那个类。
就是说:Java不会提前给你任何类,当你需要某个类的时候,再给你。而且是要一个,给一个。
不会说要一个,给你一大堆。这也是 Java 和 C 的区别之一。
假设 include
C 通过 include 关键字,将 stdio.h 头文件里面的内容全部都拿过来,导入程序。
这就好比 古时 朝廷 发赈灾款 给 某位大臣,这批钱,你怎么用都行。
而不是 先排大臣过去,碰到一项需要开支的地方,再向朝廷申请 合适的 拨款数目如果你要问:Java 和 C 那个导入方式好,肯定是java。因为 Java 是用一个,给一个,用不到的,绝对不会 给你。省空间。
不像C一样,一股脑的全给你,管你用不用,这样就会造成空间的浪费,
注意二:
但是有一个问题,通配符难道是一次性把所有的类都导入了吗?
不是,java 在处理中需要谁才导入谁
在通配符的使用过程中会出现一个问题
这两个类中都有 Date 包,编译器分辨不清,导致程序出错
这种情况下需要用完整的类名
4.创建自己的包
基本规则
- 在文件的最上方加上一个 package 语句指定该代码在哪个包中.
包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式(例如 com.bit.demo1 ).
- 包名要和代码路径相匹配. 例如创建 com.bit.demo1 的包, 那么会存在一个对应的路径 com/bit/demo1 来存储代码
- 如果一个类没有 package 语句, 则该类被放到一个默认包中
注意:
包名必须是小写的,不能是大写的
包的访问权限控制
我们已经了解了类中的 public 和 private. private 中的成员只能被类的内部使用.
如果某个成员不包含 public 和 private 关键字, 此时这个成员可以在包内部的其他类使用, 但是不能在包外部的类使用.
什么情况可以称为包的访问权限:
当你的成员变量不加任何的访问修饰限定词的时候,默认就是一个包的访问权限,只可以在当前包中使用
比如:
常见的包(系统包)
- java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。
- java.lang.reflect:java 反射编程包;
- java.net:进行网络编程开发包。
- java.sql:进行数据库开发的支持包。
- java.util:是java提供的工具程序包。(集合类等) 非常重要
- java.io:I/O编程开发包。
面向对象的基本特征
1:继承
特殊类的对象拥有其一般类的全部属性与服务,称作特殊类对一般类的继承。例如,轮船、客轮;人、大人。一个类可以是多个一般类的特殊类,它从多个一般类中继承了属性与服务,这称为多继承。例如,客轮是轮船和客运工具的特殊类。在java语言中,通常我们称一般类为父类(superclass,超类),特殊类为子类(subclass)。但我们要注意java语言是不支持多继承的,它对多继承的实现是通过接口来进行的。
子类继承父类的:大部分成员变量和大部分成员方法(不包括私有变量和私有方法)
2:抽象类和抽象方法
类中有一个abstract修饰符(但要注意只要有抽象方法的类就是抽象类)、父类中存在抽象方法(也可以没有)抽象方法没有方法体并且修饰符一定要是public或者protected,父类不能new出来
所有子类都必须实现这些抽象方法(如果没实现就必须把它也定义成一个抽象方法) 虽然不能new出来但是它可以有自己的static方法。
3:封装
某个类具有很多的方法,很多时候只管调用,不必了解具体实现,我们只要具体的结果这种是典型的“结果导向”
封装有两个含义
- 把对象的全部属性和全部服务结合在一起,形成一个不可分割的独立单位(即对象)。
- 信息隐蔽,即尽可能隐蔽对象的内部细节,对外形成一个边界〔或者说形成一道屏障〕,只保留有限的对外接口使之与外部发生联系。
封装的优点:
封装的原则在软件上的反映是:要求使对象以外的部分不能随意存取对象的内部数据(属性),从而有效的避免了外部错误对它的”交叉感染”,使软件错误能够局部化,大大减少查错和排错的难度。
4:接口实现多继承
在类中实现接口可以使用关键字implements
在类的继承中,只能做单重继承,而实现接口时,一次则可以实现多个接口,
每个接口间使用逗号“,”分隔。
多态三个条件(继承、重写、父类对象引用指向子类对象)
多态的好处:
1.可替换性(substitutability)。多态对已存在代码具有可替换性。
2.可扩充性(extensibility)。多态对代码具有可扩充性。
3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。
4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程。
一、继承
(1)什么是继承
代码中如果出现“重复代码”往往意味着一定的风险,当我们要修改这段“重复代码”时,可能要修改多处,造成代码的维护性下降。
为了避免这件事情,可以使用面向对象中的一个重要用法——
继承
继承的目的是代码重用,类的重用。把多个类之间的共同代码(共同特性)提取出来,放到"父类"中,然后再由各个子类分别继承这个父类,子类会拥有父类的属性和方法,从而就可以把重复代码消灭了。使用的
继承关键字是extends
被继承的称为父类/基类/超类,继承的类称为子类/派生类。
(2)语法规则
使用关键字 extern 进行处理,意义:可以对代码重用
代码举例:
↑↑↑↑ Dog 和 Bird 继承了 Animal 的属性(两种的共同属性)
仔细分析, 我们发现 Animal 和 Dog t以及 Bird 这几个类中存在一定的关联关系: ↓↓↓↓
- 这三个类都具备一个相同的 eat 方法, 而且行为是完全一样的.
- 这三个类都具备一个相同的 name 属性, 而且意义是完全一样的.
- 从逻辑上讲, Cat 和 Bird 都是一种 Animal
(is - a 语义)
继承中的 Dog(Bird) 可以被称为子类/派生类,Animal 可以称为父类/基类/超类,通过 extern 可以继承父类的属性(和现实中的儿子继承父亲的财产类似, 子类也会继承父类的字段和方法, 以达到代码重用的效果)
由于 Dog (Bird) 继承了父类 Animal 的属性,所以这里可以通过 (.)访问父类的属性
例如:
注意:
- 使用 extends 指定父类.
- Java 中一个子类只能继承一个父类 (而C++/Python等语言支持多继承).
- 子类会继承父类的所有 public 的字段和方法.
- 对于父类的 private 的字段和方法, 子类中是无法访问的.
- 子类的实例中, 也包含着父类的实例. 可以使用 super 关键字得到父类实例的引用
- 子类在构造的时候,要先帮助父类构造
看最后一个注意事项,当为父类提供一个构造方法时,程序会报错 !!!
报错 error
解决方式:
子类帮助父类构造,即(子类先调用父类的构造方法)
使用 super 关键字,先行调用父类,super 为显示调用构造方法
那为什么不写构造方法的时候程序不会报错???
因为当不写构造方法的时候,
编译器默认生成一个没有参数的构造方法
,
如下方的构造方法:
super 用法总结:
- super(); 调用父类的构造方法
- super.func(); 调用父类的方法
- super.name; 调用父类的成员属性
- 不能出现在静态方法中,它是依赖对象的
- super 一定出现在构造方法的第一行,其他方法中不可以
子类继承父类,子类在内存中的情况
(3)访问权限关键字
访问权限图( private | default | protected | public)
No | 范围 | private | default(包权限) | protected | public |
---|---|---|---|---|---|
1 | 同一个包中的同类 | ok | ok | ok | ok |
2 | 同一个包中的不同类 | no | ok | ok | ok |
3 | 不同包中的子类 | no | no | ok | ok |
4 | 不同包中的非子类 | no | no | no | ok |
1.同一个包中的同一个类:
2.同一个包中的不同类
3.不同包的子类(类的继承需要两个类都是public的类
4.不同包的非子类
注意事项:
- 我们希望类要尽量做到 “
封装
”, 即隐藏内部实现细节, 只暴露出 必要 的信息给类的调用者.- 因此我们在使用的时候应该尽可能的使用 比较严格 的访问权限. 例如如果一个方法能用 private, 就尽量不要用public.
- 另外, 还有一种 简单粗暴 的做法: 将所有的字段设为 private, 将所有的方法设为 public. 不过这种方式属于是对访问权限的滥用, 还是更希望大家能写代码的时候认真思考, 该类提供的字段方法到底给 “谁” 使用(是类内部自己用, 还是类的调用者使用, 还是子类使用).
(4)final 关键字
如果一个类不想被继承,可以把该类设置为被 final 修饰
总结 final 修饰:
- final 修饰常量,不可被修改
- final 修饰类,不可被继承
- final 修饰方法,方法不可重写,属性不可覆盖
1.final关键字修饰常量:常量不可被修改,并且需要赋初值才能使用。例:
2.final关键字修饰类:这个类不能被继承。
我们经常使用的String字符串类就是被final修饰的类,因此它无法被继承。
3.final关键字修饰方法:方法不能够被重写。
二、组合
和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果。
组合并没有涉及到特殊的语法(诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段
.这是我们设计类的一种常用方式之一.
- 组合表示 has - a 语义
在刚才的例子中, 我们可以理解成一个学校中 “包含” 若干学生和教师.
- 继承表示 is - a 语义
在上面的 “动物和猫” 的例子中, 我们可以理解成一只猫也 “是” 一种动物.
例如:
①学校包含两个学生和两个老师
②圆中包含原点和半径