初识java的小伙伴看到包,肯定会想,包?是挎在肩上的名贵包包吗?哈哈,博主开玩笑了,当然了在java中的包。
引言:
假如说在公司的日常生产开发中,你建立了一个TestDemo.java文件,而你的同事也建立了一个TestDemo.java文件,如果你们两个人要完成同一个项目,那么由于用相同的文件名,编译器就会反应异常。所以我们在这就引出了包。在不同的包中创建相同的java文件,是不会报错的。
包是组织类的一种方式。
使用包的主要目的是保证类的唯一性,其实包就相当于一个文件而已。
如果要用到包中的哪个类,具体导入就可以了。
类似于我们要实现输入某一个数,就要用到Scanner类,我们可以查找java使用手册,在util包下就有Scanner类,在导入包中类的过程中,我们要用到import关键字,例如import java.util.Scanner,我们就成功的导入了util包中Scanner类,还有我们在操作一个数组时,要用到util包下的Arrays类,也就是import java.util + util包中的Arrays类,这样就成功的导入了。java为我们带来的许多便利,类似于输入,数组的某些操作等,这些功能都在包中实现,不需要我们手动实现。java包的导入就像C/C++的include都是要把一些文件导入项目中去。但是他们之间也有不同之处,如果为了省事,或者不知道代码要用到util包下的某一个类,或者要调用其包下的类,我们也可以这样import.java.util, *为通配符,如果我们在写代码的过程中要用到util包下的某一个类,我们无需其他操作import java.util*会自动的导入我们所需要的的类,而不是导入util包下的所有类。而在C/C++中需要把include下的所有文件全部导入。
代码演示:
import java.util.Arrays; //导入util包下的数组类
import java.util.Scanner; //导入util包下的Scanner类
public class TestDemo1 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int a = scanner.nextInt();
int []array = {
1,2,3,4,5,6};
System.out.println(Arrays.toString(array));
}
}
使用通配符,导入包中的类*
import java.util*;//导入代码中所需要的的在util包下的类
public class TestDemo1 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int a = scanner.nextInt();
int []array = {
1,2,3,4,5,6};
System.out.println(Arrays.toString(array));
}
}
其实我们可以不用import关键字,可以之间在调用包中的类
public class Test {
public static void main(String[] args) {
java.util.Date date = new java.util.Date();
// 得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
}
但是在实际写代码的过程中,我们很少这样使用。
而且推荐大家使用显示的调用包中的相关类,通配符虽然便利但是在有一些场合中会引来不必要的麻烦
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());
}
}
使用 import static 可以导入包中的静态的方法和字段
import java.util.lang.System*
public class Test {
public static void main(String[] args) {
out.println("hello");
}
}
虽然这样看起来很简洁,但是还是不建议使用,代码的可读性不高。
使用这种方式很简洁,我们在调用包中的类时,要分情况使用,不能一味地为了代码的简洁性,而忽略了代码的可读性,这样得不偿失。
import static java.lang.Math.*;
public class Test {
public static void main(String[] args) {
double x = 30;
double y = 40;
// 静态导入的方式写起来更方便一些.
// double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
double result = sqrt(pow(x, 2) + pow(y, 2));
System.out.println(result);
}
}
基本规则
在文件的最上方加上一个 package 语句指定该代码在哪个包中.
包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式(例如 com.bit.demo1 ).
包名要和代码路径相匹配. 例如创建 com.bit.demo1 的包, 那么会存在一个对应的路径 com/bit/demo1 来存 储代码.
如果一个类没有 package 语句, 则该类被放到一个默认包中.
新建一个包,并且在包中创建一个类
2.为新建的这个包命名(最好命名为公司域名的倒置,博主现在没有自己的公司,先这样吧)
3.在包中新建一个类
博主在文章的前面说了,在不同的包中了创建相同的文件这样就会消除文件之间冲突。
package com.bit;
public class TestDemo {
public static void main(String[] args) {
System.out.println("hello world");
}
}
package com;
public class TestDemo {
public static void main(String[] args) {
System.out.println("hello world");
}
}
com 包下的TestDemo.java文件和com.bit包下的TestDemo.java文件不会发生冲突
我们在学习java面向对象编程时,学到了public ,private关键字,其中被private修饰的成员变量和成员方法都只能在所在当前的类中使用,其他类无法进行访问。在包中如果一个类或者成员变量没有被public 或者 private修饰时,是默认的,即只能在当前类所在的包中访问。
相同的包中类之间可以互相调用
package com.bit;
public class Test1 {
int age;
String name;
}
package com.bit;
public class Test2 {
public static void main(String[] args) {
Test1 test1 = new Test1();
test1.age = 10;
test1.name = "zhangsan";
System.out.println(test1.age);
System.out.println(test1.name);
}
}
运行成功,输出10和zhangsan
调用不同包中类的成员变量
package com.bit;
public class Test2 {
public static void main(String[] args) {
Test3 test3 = new Test3();
test3.age = 10;
test3.name = "zhangsan";
System.out.println(test3.age);
System.out.println(test3.name);
}
}
package com.bit.demo;
public class Test3 {
int age;
String name;
}
编译错误
java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。
java.lang.reflect:java 反射编程包;
java.net:进行网络编程开发包。
java.sql:进行数据库开发的支持包。
java.util:是java提供的工具程序包。(集合类等) 非常重要
java.io:I/O编程开发包
当面向对象编程的小白看到继承时,应该会想继承?是继承百万家产的那个意思吗?哈哈意思差不多。
也就是父亲的家产变成了儿子的,这就是继承。
根据继承的思想,实现一个动物类
class Animal{
public int age; //动物年龄
public String sex; //动物性别
public String name;//动物名字
public void eat(){
System.out.println(name + "正在吃"); //动物都具有的特性 吃
}
public void sleep(){
System.out.println(name + "正在睡"); //动物都具有的特性 睡
}
}
然后我们在实现一个小猫,和小狗类
class Cat{
public int age;
public String sex;
public String name;
public String longtail;
public void eat(){
System.out.println(name + "正在吃");
}
public void sleep(){
System.out.println(name + "正在睡");
}
public void UpTree(){
System.out.println(name + "上树");
}
}
class Dog{
public int age;
public String sex;
public String name;
public String color;
public void eat(){
System.out.println(name + "正在吃");
}
public void sleep(){
System.out.println(name + "正在睡");
}
public void swim(){
System.out.println(name + "游泳");
}
}
根据上面的代码,我敢肯定仔细的友友们一定会发现在动物类中的成员变量和成员方法,在猫类和狗类中都有,也因为猫和狗都是动物,有着相同的属性,同时也用着彼此不同的属性。
这三个类都具备一个相同的 eat 方法, 而且行为是完全一样的.
这三个类都具备一个相同的 name 属性, 而且意义是完全一样的.
从逻辑上讲, Cat 和 Dog 都是一种 Animal (is - a 语义).
此时我们就可以让 Cat 和 Dog分别继承 Animal 类, 来达到代码重用的效果.
此时,== Animal 这样被继承的类, 我们称为 父类 , 基类 或 超类, 对于像 Cat 和 Dog 这样的类, 我们称为 子类, 派生类 和现实中的儿子继承父亲的财产类似, 子类也会继承父类的字段和方法, 以达到代码重用的效果.==
class 子类 extends 父类 {
}
使用 extends 指定父类.
Java 中一个子类只能继承一个父类 (而C++/Python等语言支持多继承).
子类会继承父类的所有 public 的字段和方法.
对于父类的 private 的字段和方法, 子类中是无法访问的.
子类的实例中, 也包含着父类的实例,可以使用super关键字实现对父类中的引用。
在java语言中不支持多继承,也就是说,子类至多只有一个父类,但是可以通过接口来实现多重继承的目的
继承存在的意义:减少代码的冗余,实现代码的复用
怎样有效的设计继承:抽取类中的公共部分放到一个类中,使用extends进行继承,实现代码的复用
实现上述猫类和狗类继承动物类
class Animal{
public int age;
public String sex;
public String name;
public void eat(){
System.out.println(name + "正在吃");
}
public void sleep(){
System.out.println(name + "正在睡");
}
}
class Cat extends Animal{
public String longtail;
public void UpTree(){
System.out.println(name + "上树");
}
}
class Dog extends Animal{
public String color;
public void swim(){
System.out.println(name + "游泳");
}
}
public class TestDemo {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "旺财";
dog.eat();
dog.swim();
Cat cat = new Cat();
cat.name = "mimi";
cat.UpTree();
cat.eat();
}
}
//运行结果:
//旺财正在吃
//旺财游泳
//mimi上树
//mimi正在吃
在上面我们提到了super关键字,那就根据代码看看它的具体功能吧
我们知道要创建一个对象时,首先就是为它分配内存,然后就是为它构造方法,当我们没有定义构造方法时,系统会自动的为其创建一个默认无参构造方法。
class Animal{
public int age;
public String sex;
public String name;
public Animal(int age,String sex,String name){
//如果想在Animal类中初始化动物的属性,那么就要对其进行初始化,这就让我们想起了构造方法,但是光在父类中实现构造函数,子类中会发生异常
this.age = age;
this.sex = sex;
this.name = name;
}
public void eat(){
System.out.println(name + "正在吃");
}
public void sleep(){
System.out.println(name + "正在睡");
}
}
子类继承父类,首先帮父类进行构造
那让我们看看是怎样进行构造的
class Cat extends Animal{
//显示调用父类的构造方法
public Cat(int age,String sex,String name){
super(age,sex,name);
}
public String longtail;
public void UpTree(){
System.out.println(name + "上树");
}
}
在子类继承父类之前,super调用父类的构造方法,帮助父类进行构造
高频面试题:
说一说this关键字和super关键字的区别?
this关键字
this
表示当前对象的引用
this()
表示调用当前类的构造方法
this.data
表示调用当前类中的成员变量
this.func()
表示调用当前类中的成员方法
super关键字
super
表示当前对象父类的引用(此说法有漏洞,参考this)
super()
表示调用父类的构造方法
super.data
表示调用父类中的成员变量
super.func
表示调用父类中的成员方法
不知道大家发现了没有,当我们调用一个类中的成员变量时,不是被public 修饰,就是被private修饰,如果是public 修饰,权限就会变成公有的,无论在哪都可以访问到将要调用的成员变量,这样就失去了类的封装性,这样就成我们写的程序变得不安全,但是如果是private修饰的话,虽然满足了类的封装性,但是类外的成员无法访问到该类中的成员属性。所以我们取中,引出可protected关键字。
NO | 范围 | private | default | protected | public |
---|---|---|---|---|---|
1 | 同一包中同一类 | √ | √ | √ | √ |
2 | 同一包中不同类 | √ | √ | √ | |
3 | 不同包中的子类 | √ | √ | ||
4 | 不同宝中的非子类 | √ |
那我们该何时使用怎样的访问权限修饰限定符呢?
1.我们希望类要尽量的封装,保证类的封装性,指把内部实现细节隐藏,只暴露必要的条件共调用者调用。如果类中的一个方法能使用private修饰,就不要有protected修饰。
2.还有类中的成员变量一般使用private进行修饰,如果现在类外调用可以实现getter和setter方法对其进行调用。
我们学到这里继承的知识也应该了解了不少了吧,那就看看这一问:如果父类和子类中都用相同的成员变量,我们在调用时到底调用的时哪个?
请看如下代码:
class Base{
public int a = 1;
public int b = 2;
}
class Derieve extends Test1{
public int a = 3;
public void func(){
System.out.println("a = " + a); //调用子类中的成员变量
System.out.println("a = " + super.a); //调用父类中的成员变量
}
}
public class TestDemo {
public static void main(String[] args) {
Test2 test2 = new Test2();
test2.func();
}
}
//输出结果 a = 3 a = 1
当调用父类和子类相同的成员变量时,默认调用子类的成员变量,如果要调用父类中的成员变量,就要用super关键字修饰。还有super关键字不能在static 下使用。
说说这继承复杂不?哈哈哈我们一般在用到继承的时候最多不超过三层继承,如果代码需要继承的层数过多就要考虑代码的重构。
曾经我们学习过 final 关键字, 修饰一个变量或者字段的时候, 表示 常量 (不能修改)
class TestDemo{
public static void main(String[] args) {
final int a = 10;
a = 20; //报错
System.out.println(a);
}
}
final 关键字也可以用到类中,如果想让一个类不能被修改,或者在继承表明某个类不能被继承
final class Animal{
··············
}
class Cat extends Animal{
//Animal标红,表示Animal类不能被继承
··············
}
和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果. 例如表示一个学校:
public class Student {
...
}
public class Teacher {
...
}
public class School {
public Student[] students;
public Teacher[] teachers;
}
组合并没有涉及到特殊的语法(诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段. 这是我们设计类的一种常用方式之一.
组合表示 has - a 语义 在刚才的例子中, 我们可以理解成一个学校中 “包含” 若干学生和教师.
继承表示 is - a 语义 在上面的 “动物和猫” 的例子中, 我们可以理解成一只猫也 “是” 一种动物. 大家要注意体会两种语义的区别