一、包
1.1包的基础概念
1.2包的本质
包的本质实际上就是创建不同的文件夹来保存类文件,示意图如下:
包就是两个文件夹,同一个包下方法的名称不能相同,但不同包下方法的名称可以相同。虽然名称相同,但这可以是两个完全不相同的类。
1.3包的基本代码
引入包
package com.use;
import com.baostudy.Dog;
public class test {
public static void main(String[] args) {
Dog dog = new Dog();
com.modifierStudy.Dog dog1 = new com.modifierStudy.Dog();
/*
为了区分两个dog,下面的用包名进行区分
本质用途还是一样的。
*/
}
}
一些常见的包
1.4包的相关细节
二、访问修饰符
2.1访问修饰符的基本概念
2.2访问修饰符的相关细节
三、封装
3.1封装的基础概念
封装就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序其它部分只有通过被授权的操做[方法],才能对数据进行操作。(电视机就是一个例子,开关电视机在电视机内部是一个非常复杂的过程,但对于用户来说只需要按一下开关键。用户无法改变内部结构。)
3.2封装的实现
3.3封装的实例代码
要求如下:
package com.ssj.encap;
public class Encapsulation01 {
public static void main(String[] args) {
Person person = new Person();
person.setName("jack");
person.setSalary(30000);
person.setAge(30);
System.out.println(person.name);
//工资和年龄只有通过get才能查到,不能直接查到
//可以在get上增加一些逻辑比如:密码。才能查询
person.getSalary("admin");
person.getAge("aaaaa");
}
}
class Person{
public String name;
private int age;
private double salary;
//自己写setxxx和getxxx太慢了,使用快捷键。
//alt+insert选择(Getter and Setter)
//然后根据要求完善代码
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void getAge(String lock) {
if(lock == "admin") {
System.out.println(age);
}
else{
System.out.println("密码错误,没有权限访问年龄");
}
}
public void setAge(int age) {
if (age >= 1 && age <= 120) {
this.age= age;
}
else{
System.out.println("你设置的年龄不对,年龄需要在 1-120 ,给你默认年龄18");
this.age = 18;
}
}
public void getSalary(String lock) {
if(lock == "admin") {
System.out.println(salary);
}else{
System.out.println("密码错误,没有权限访问工资");
}
}
public void setSalary(double salary) {
this.salary = salary;
}
}
由上可知封装的好处:1.可以隐藏实现细节2.可以对数据进行验证(set方法),保证安全合理(在get中增加逻辑)。
上述代码有个问题,因为在实际应用的过程中会顺手写构造器,以便随时能用。(就不用一个参数一个set方法了)如果使用构造器进行赋值的话就可以绕过set方法,这样就不能验证了。解决代码如下:
public Person(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
setSalary(salary);
setName(name);
setAge(age);
}
在构造器中调用set方法就可以避免这个问题了。
package com.ssj.encap;
public class Encapsulation01 {
public static void main(String[] args) {
Person person = new Person("jack",30,30000);
System.out.println(person.name);
person.getSalary("admin");
person.getAge("aaaaa");
//工资和年龄只有通过get才能查到,不能直接查到
//可以在get上增加一些逻辑比如:密码。才能查询
}
}
class Person{
public String name;
private int age;
private double salary;
//自己写setxxx和getxxx太慢了alt+insert
//选择(Getter and Setter)
//然后根据要求完善代码
public Person(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
setSalary(salary);
setName(name);
setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void getAge(String lock) {
if(lock == "admin") {
System.out.println(age);
}
else{
System.out.println("密码错误,没有权限访问年龄");
}
}
public void setAge(int age) {
if (age >= 1 && age <= 120) {
this.age= age;
}
else{
System.out.println("你设置的年龄不对,年龄需要在 1-120 ,给你默认年龄18");
this.age = 18;
}
}
public void getSalary(String lock) {
if(lock == "admin") {
System.out.println(salary);
}else{
System.out.println("密码错误,没有权限访问工资");
}
}
public void setSalary(double salary) {
this.salary = salary;
}
}
四、继承
4.1继承的基础概念
先看两段代码;
package com.extend;
//大学生考试
public class Graduate {
public String name;
public int age;
private double score;
public void setScore(double score) {
this.score = score;
}
public void testing(){
System.out.println(" 大学生 " + name + " 正在考大学数学 ");
}
public void showInfo(){
System.out.println(" 学生名 " + name + " 年龄 " + age + " 成绩 " + score);
}
}
package com.extend;
//小学生考试
public class pupil {
public String name;
public int age;
private double score;
public void setScore(double score) {
this.score = score;
}
public void testing(){
System.out.println(" 小学生 " + name + " 正在考小学数学 ");
}
public void showInfo(){
System.out.println(" 学生名 " + name + " 年龄 " + age + " 成绩 " + score);
}
}
通过看上述两段代码不难发现,代码中有很多重复的部分也有不重复的部分,对于重复部分其实是学生的共有属性,重复写很麻烦,可以采取继承的方式解决这一问题。
4.2继承的基本代码
对于开头的代码运用继承进行优化。
父类:
package com.extend.improve_;
//父类:是pupil和graduate的父类
public class student {
//共有属性
public String name;
public int age;
private double score;
//共有方法
public void setScore(double score) {
this.score = score;
}
public void showInfo(){
System.out.println(" 学生名 " + name + " 年龄 " + age + " 成绩 " + score);
}
}
子类:
package com.extend.improve_;
public class pupile extends student{
public void testing(){
System.out.println(" 小学生 " + name + " 正在考小学数学 ");
}
}
package com.extend.improve_;
public class Graduate extends student{
public void testing(){
System.out.println(" 大学生 " + name + " 正在考大学数学 ");
}
}
主函数
package com.extend.improve_;
public class Extends01 {
public static void main(String[] args) {
pupile pupile = new pupile();
pupile.name = "银角大王";
pupile.age = 10;
pupile.testing();
pupile.setScore(60);
pupile.showInfo();
System.out.println("========");
Graduate graduate = new Graduate();
graduate.name = "金角大王";
graduate.age = 22;
graduate.testing();
graduate.setScore(100);
graduate.showInfo();
}
}
4.3继承的本质
4.4继承的相关细节
(1)子类继承了所有的属性和方法,但是私有(private)属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问。
private int name = 10;
public void getName{
System.out.println(name)
}
private void test400(){
System.out.println("test400");
}
public void getTest400(){
test400();
}
(2)子类必须调用父类的构造器,完成父类的初始化。
(3)当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中使用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过。[对于上面这段话可以一句一句去理解]
当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器
package com.extend.improve_;
public class Sub extends Base {
public Sub(){
//super()默认调用父类的无参构造器
System.out.println("子类sub()构造器被调用");
}
//当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器
public Sub(String name){
System.out.println("子类Sub()构造器被调用");
}
public void sayOk(){
//非私有的属性和方法可以在子类直接访问
//但是私有属性和方法不能在子类直接访问
System.out.println(n1+" "+n2+" "+n3);
test100();
test200();
test300();
}
}
package com.extend.improve_;
public class Base {
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public Base(){
System.out.println("父类Base()构造器被调用");
}
public int gtN4(){
return n4;
}
public void test100(){
System.out.println("test100");
}
protected void test200(){
System.out.println("test200");
}
void test300(){
System.out.println("test300");
}
private void test400(){
System.out.println("test400");
}
public void getTest400(){
test400();
}
}
package com.extend.improve_;
public class extemdsDetail {
public static void main(String[] args) {
Sub sub = new Sub();//创建一个子类对象
System.out.println("===第二个对象===");
Sub sub1 = new Sub("jack");
}
}
通过上述代码及其运行结果可以看出,只调用了子类的构造器,父类的构造器也被调用了。
如果父类没有提供无参构造器,则必须在子类的构造器中使用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过。
因为子类中的super()默认(super是隐含存在的,只是编译器自带的)调用父类的无参构造器,而父类没有加无参构造器,因此代码报错。解决办法:
package com.extend.improve_;
public class Sub extends Base {
public Sub(){
super("smith",10);
System.out.println("子类sub()构造器被调用");
}
//当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器
public Sub(String name){
super("tom",30);//因为父类中没有无参构造器
//需要super去指定调用父类的哪一个构造器
System.out.println("子类Sub()构造器被调用");
}
public void sayOk(){
//非私有的属性和方法可以在子类直接访问
//但是私有属性和方法不能在子类直接访问
System.out.println(n1+" "+n2+" "+n3);
test100();
test200();
test300();
}
}
(4)如果希望指定去调用父类的某个构造器,则显式的调用一下:super()
(5)super在使用时,需要放在构造器的第一行(因为是先调用父类的构造在再调用子类的构造器)
(6)super和this都只能放在构造器的第一行。因次这两个方法不能同时存在在同一个构造器内
(7)java所有类都是object类的子类(通过快捷键ctrl+H(IEDA))
(8)父类构造器的调用不限于直接父类,将一直往上追溯直到Object(顶级父类)
(9)子类最多只能继承一个父类,即java中是单继承机制,即(A->B,A->C(->代表继承))是不可实现的。
(10)不能滥用继承,子类和父类必须满足is -a的逻辑关系
五、super关键字
5.1super关键字的基础概念
super代表父类的引用,用于访问父类的属性、方法、构造器。
(1)访问父亲的属性,但不能访问父亲的private属性
(2)访问父亲的方法,但不能访问父亲的private方法
(3)访问父亲的构造器
5.2super关键字的基础代码
父类:
package com.super_;
public class A {
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public A(){}
public A(String name){}
public A(String name,int age){}
public void test100(){
}
public void test200(){
}
void test300(){
}
private void test400(){
}
}
子类:
package com.super_;
public class B extends A{
//访问父类的属性,但不能访问父类的private属性
public void hi(){
System.out.println(super.n1+" "+super.n2+" "+super.n3);
}
//访问父类的方法,但不能访问父类的private方法
public void ok(){
super.test100();
super.test200();
super.test300();
//super.test400();不能访问父类私有的方法
}
//访问父类的构造器:super(参数列表);只能放在构造器的第一句,只能出现一句!
public B(){
super();
//super("jack");
//super("jack",10);
}
}
5.3super关键字的相关细节
1.调用父类构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子类初始化)
2.当子类中有和父类中的成员(属性和方法)重名时,为了访问父亲的成员,必须通过super。如果没有重名,使用super、this、直接访问时一样的效果。
3.super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类(上级类)中有同名成员,使用super访问遵循就近原则。