本文主要是介绍java学习基础课之面向对象(渡一教育)【修饰符】(六),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 一、权限修饰符
- 二、特征修饰符
- 1. final
- 2. static
- 三、设计模式
- 四、单例模式(Singleton)
- 五、存在继承关系的类 加载机制 及执行过程
- 六、native
- 七、abstract
- 八、接口
修饰符
权限修饰符
public 公共的
protected 受保护的
默认不写 默认的
private 私有的
特征修饰符
final 最终的 不可更改的
static 静态的
abstract 抽象的
native 本地的
transient 瞬时的 短暂的------>序列化
synchronized 同步的 线程问题
volatile 不稳定的
一、权限修饰符
public 公共的 本类 同包 子类 当前项目中任意类的位置只要有对象都可以访问
protected 保护的 本类 同包 子类(通过子类对象在子类范围内部访问)
默认不写 默认的 本类 同包
private 私有的 本类
可以修饰类及类成员(除了块)
修饰类的时候只允许两个 public , 默认不写
新建一个包packa
packa中定义一个类TestA:
package packa;public class TestA {public static void main(String[] args){TestA ta = new TestA();ta.testPublic();ta.testProtected();ta.testDefault();ta.testPrivate();}//四个修饰符在本类中都可以访问public void testPublic(){System.out.println("我是TestA类中的public修饰符方法");}protected void testProtected(){System.out.println("我是TestA类中的protected修饰符方法");}void testDefault(){System.out.println("我是TestA类中的默认不写修饰符方法");}private void testPrivate(){System.out.println("我是TestA类中的private修饰符方法");}}
四个修饰赋在本类中都可以访问。
同一个包中,再定义一个新的类TestAA:
package packa;
//把TestA中的主方法,放在TestAA中,测试四个修饰符的访问权限。
public class TestAA {public static void main(String[] args){TestA ta = new TestA();ta.testPublic();ta.testProtected();ta.testDefault();//ta.testPrivate();//报错,这是私有的,只能在本类中被访问}
}
私有的修饰符,只能在本类中被访问。其他三个在同包中都可以访问。
在packa中再建立一个包,inner
inner中在建立一个新的类,TestInnerA:
package packa.innera;import packa.TestA;public class TestInnerA {public static void main(String[] args){TestA ta = new TestA();ta.testPublic();//ta.testProtected(); //不好用,报错//ta.testDefault();//不好用,报错//ta.testPrivate();//不好用,报错,私有的}//说明和packa不是同包。
}
TestA和TestInnerA不是同一个包。package 后面的名字不一样,就不是一个包。
新建一个包,packb,这个包和packa并列。
packb中建立一个TestB:
package packb;
import packa.TestA;public class TestB extends TestA{ //TestB是TestA的子类,所以在这个子类范围内可以访问TestA的成员public void testB(){this.testPublic();//子类可以访问父类的共有方法this.testProtected();//子类可以访问父类的保护方法}public static void main(String[] args){TestB tb = new TestB();tb.testPublic();//可以调用。子类可以访问父类的共有方法tb.testProtected();//通过继承,可以调用。子类可以访问父类的保护方法TestA ta = new TestA();ta.testPublic();// ta.testProtected();//报错!继承的子类TestB可以访问保护成员,自己却不能访问保护成员。//因为保护成员,只能在本类,同包和子类(通过子类对象在子类范围内部访问)中访问,你这个不是子类对象,也不是本类,不是同包。}
}
//但是一旦出了TestB这个子类的范围,就会报错。比如,你将主方法放在子类的外面,类似下面注释那样,就会报错。
但是一旦出了TestB这个子类的范围,就会报错。比如,你将主方法放在子类的外面,类似下面注释那样,就会报错。
package test;import packb.TestB;public class TestMain {public static void main(String[] args){TestB tb = new TestB();tb.testPublic();//tb.testProtected();//报错,因为不在子类的范围内了。}
}
保护成员只能在本类,同包和子类(通过子类对象在子类范围内部访问)中访问。本类和同包比较容易理解,主要这个子类,重点一:是子类的对象。重点二:是子类范围内部。
私有成员的好处,控制你的输入,不会让你随便修改属性的值,而且可以通过方法判断你给的值,是否合适。例子如下:
package person;public class Person {//属性public String name;private int age;public String sex;//方法//设计一个方法 用来取得age属性的值// 提供条件?不需要 返回值? 获取的age的值public int getAge(){//ifreturn this.age;}//设计一个方法 用来给age属性赋值// 提供条件? age的值 返回值?voidpublic void setAge(int age){if(age<0){System.out.println("对不起 您还没出生呢 请给正确的年龄范围");this.age = -1000;//抛出异常}else if(age>130){System.out.println("对不起 您已经升仙啦 请给正确的年龄范围");this.age = -1000;//抛出异常}else {this.age = age;}}
}
主方法:
package person;public class Test {public static void main(String[] args){//创建类的过程是在Java中描述的过程//1.创建对象Person p = new Person();//2.对象的引用 . 调用属性p.name = "郑中拓";p.setAge(18); //如果设置的值不合理,会提醒你的。你也不能随意设置不合理的值了。p.sex = "男";System.out.println("今年"+p.getAge());
//以前可以通过p.age直接访问属性了,
//但是由于我们把属性设置成了私有的,所以需要方法进行访问了。}
}
Java类和类之间的关系
继承 关联 依赖
Java面向对象的四个特征
继承 封装 多态 (抽象)
封装 : 将一些数据或执行过程 进行一个包装
目的 : 保护这些数据 或 执行过程的安全
- 对属性本身的封装:
属性私有(封装在类中)
提供操作属性相应的方式(公有的方法) - 以后强烈建议大家属性不要公有的---->非常不安全
- 既然以后大家都这样操作属性 , 属性及其操作属性的方法都有其命名的规约
age------> setAge getAge
myAge–> setMyAge getMyAge
二、特征修饰符
1. final
1.可以修饰什么
2.修饰以后有什么特点
- 修饰变量
- 修饰属性
- 修饰方法
- 修饰类本身
- 修饰变量
- 如果在定义变量时没有赋初始值,给变量一次存值的机会(因为变量在栈内存空间内 没有默认值 如果不给机会 就没法用啦)
- 一旦变量被存储了一个值, 若用final修饰后 则不让再次改变 ----> 相当于常量啦(值没法动)
package test_final;public class TestFinal {public static void main(String[] args){final int a = 1;//声明变量 内存开辟栈内存空间//上面那一句也可以写成下面的两行/* final int a ;a = 1;*///如果在定义变量时没有赋初始值//给变量一次存值的机会(因为变量在栈内存空间内 没有默认值 如果不给机会 就没法用啦)a = 10;//报错//一旦变量被存储了一个值 若用final修饰后 则不让再次改变 ----> 相当于常量啦(值没法动)}
}
- 注意变量类型是基本类型还是引用类型
- 如果修饰的变量是基本数据类型,则变量内的值不让更改—常量
- 如果修饰的变量是引用数据类型 ,则变量内的地址引用不让更改—对象唯一
package test_final;public class TestFinal {final int[] x;x = new int[]{1,2,3};x[0] = 10;x[0] = 100;//不报错!因为我们改的是栈内存里的值,而不是改了x的地址// x = new int[5];//这就会报错。因为试图修改引用的地址,肯定报错。}
}
- 修饰属性
- 全局变量,存储在堆内存的对象空间内一个空间
- 属性如果没有赋值 ,有默认值存在的,所以,属性用final修饰后,必须给属性赋初值,否则编译报错
private final String name = "";
空值都行,但是必须给初值。 - 特点与修饰变量一致
注意变量类型是基本类型还是引用类型
如果修饰的变量是基本数据类型 ,则变量内的值不让更改—常量
如果修饰的变量是引用数据类型 ,则变量内的地址引用不让更改—对象唯一
- 修饰方法
方法是最终的方法,不可更改。
子类继承父类的方法 , 将父类的方法重写(覆盖)
- final修饰的方法 ,要求不可以被子类重写(覆盖)。
父类:
package test_final;public class Animal {public void eat(){System.out.println("动物的吃饭方法");}
}
子类:
package test_final;public class Person extends Animal{//extends-->扩展public void eat(){System.out.println("子类重写(覆盖)父类的吃饭方法");}
}
主方法:
package test_final;public class TestFinal {public static void main(String[] args){Person p = new Person();p.eat();}
}
//这是测试重写,完全没有问题。
但是一旦我将父类的方法,利用final修饰,子类就不可以重写了。
package test_final;public class Animal {public final void eat(){System.out.println("动物的吃饭方法");}
}
子类重写eat时会报错的。
package test_final;public class Person extends Animal{//报错!不可以重写。public void eat(){System.out.println("子类重写(覆盖)父类的吃饭方法");}
}
- 修饰类本身
- 类是最终的 ,不可以更改
- (太监类 无后) 此类不可以被其他子类继承
- 通常都是一些定义好的工具类
Math Scanner Integer String
2. static
1.可以修饰什么
2.修饰后有什么特点
1.可以修饰 :
- 修饰属性
- 修饰方法
- 修饰块
- 修饰类(内部类)
- 特点:
- (1)静态元素在类加载时就初始化啦,创建的非常早,此时没有创建对象
- (2)静态元素存储在静态元素区中,每一个类有一个自己的区域,与别的类不冲突
- (3)静态元素只加载一次(只有一份),全部类对象及类本身共享
- (4)由于静态元素区加载的时候,有可能没有创建对象,可以通过类名字直接访问
- (5)可以理解为静态元素不属于任何一个对象,属于类的
- (6)内存管理,栈内存创建开始用完即回收,堆内存通过GC回收。静态元素区Garbage Collection无法管理,可以粗暴的认为常驻内存
- (7)非静态成员(堆内存对象里)中可以访问静态成员(静态区)
- (8)静态成员中可以访问静态成员(都存在静态区)
- (9)静态成员中不可以访问非静态成员(个数 一个出发访问一堆相同名字的东西 说不清)(静态元素属于类 非静态成员属于对象自己)
- (10)静态元素中不可以出现this或super关键字(静态元素属于类,不属于对象,所以this和super就说不清楚了。)
不用static的代码:
public class Person {public String name; //暂时用public讲,方便。实际最好设置为私有的。public int age;//斜体public static void main(String[] args){Person p1 = new Person();p1.name = "阿拓小哥哥";p1.age = 18;Person p2 = new Person();// p2 =p1;//如果加上这句话,两个输出都是:姬成小姐姐了。p2.name = "姬成小姐姐";p2.age = 16;//第二个对象使用的age就是第一个对象的ageSystem.out.println(p1.name+"今年"+p1.age+"岁");System.out.println(p2.name+"今年"+p2.age+"岁");}
}
//输出结果:
//阿拓小哥哥今年18岁
//姬成小姐姐今年16岁
// p2 =p1;//如果加上这句话,两个输出都是:姬成小姐姐今年16岁
加上static以后:
//age加上了static特征修饰符
public class Person {public String name; //暂时用public讲,方便。实际最好设置为私有的。public static int age;//斜体public void test(){System.out.println("我是普通方法"+Person.age); //非静态方法可以访问静态成员}public static void testStatic(){System.out.println("我是静态方法");} //静态方法可以访问静态成员 //但是不可以访问非静态成员,因为一个静态方法,对应着好多的对象,不知道访问哪一个对象的成员了。public static void main(String[] args){Person p1 = new Person();p1.name = "阿拓小哥哥";p1.age = 18;Person p2 = new Person();p2.name = "姬成小姐姐";p2.age = 16;//第二个对象使用的age就是第一个对象的ageSystem.out.println(p1.name+"今年"+p1.age+"岁");System.out.println(p2.name+"今年"+p2.age+"岁");}
}
//结果:
//阿拓小哥哥今年16岁 ???为什么是16岁呢??
//姬成小姐姐今年16岁
//原因只可能是:第二个对象使用的age就是第一个对象的age
那么static修饰的存在哪了呢??实际上存在了静态元素区。
age存在了静态元素区。
- 小任务
书店买书
按照买书人的身份做相应的折扣
1.书店内部人员 管理员 5折-------0
2.书店的VIP VIP会员 8折-------1
3.普通路人 普通 全价-------2
package bookstroe;/**书店类*/
public class BookStore {private static final int BOOKSTROE_ADMIN = 0;private static final int BOOKSTROE_VIP = 1;private static final int BOOKSTROE_NORMAL = 2;
//为什么加static?是因为用了static,就不用创建对象,通过类名字就可以直接访问了,BookStore.BOOKSTROE_ADMIN
//为什么加final?为了让这个变量值不再改变了。public void buyBook(float price,int identity){switch(identity){case BookStore.BOOKSTROE_ADMIN:System.out.println("尊敬的书店管理员,您购买的图书应付款:"+price*0.5);break;case BookStore.BOOKSTROE_VIP:System.out.println("尊敬的书店VIP客户,您购买的图书应付款:"+price*0.8);break;case BookStore.BOOKSTROE_NORMAL:System.out.println("尊敬的普通用户,您购买的图书应付款:"+price);break;default:System.out.println("对不起,系统查不到您的身份,不许买书");}}
}
package bookstroe;import java.util.Scanner;public class TestMain {public static void main(String[] args){BookStore bookStore = new BookStore();Scanner input = new Scanner(System.in);System.out.println("请输入图书金额");float price = input.nextFloat();System.out.println("请出示您的身份");int identity = input.nextInt();bookStore.buyBook(price,identity);}
}
命名规约
类名首字母大写
属性 方法 变量首字母小写 第二个大写
构造方法 与类名一致 首字母大写
包 全部字母小写 注意区分关键字
静态常量 全部字母大写 _
私有属性对应的方法 getName/setName
见名知义
三、设计模式
设计模式 23种 (内功心法)
设计模式不是知识点;
设计模式是一种设计经验的总结;
设计模式用来解决某些场景下的某一类问题的---->通用的解决方案;
有了设计模式之后 可以让代码更容易被理解 确保了复用性 可靠性 可扩展性。
设计模式分为三类
- 1.创建型模式(5种)----->用于解决对象创建的过程
单例模式;工厂方法模式;抽象工厂模式;建造者模式; 原型模式 - 2.结构型模式(7种)----->把类或对象通过某种形式结合在一起 构成某种复杂或合理的结构
适配器模式;装饰者模式 ;代理模式;外观模式;桥接模式 组合模式;享元模式 - 3.行为型模式(11种)---->用来解决类或对象之间的交互 更合理的优化类或对象之间的关系
观察者模式 ;策略模式;模板模式;责任链模式; 解析器模式 ;迭代子模式
命令模式;状态模式;备忘录模式; 访问者模式; 中介者模式
四、单例模式(Singleton)
设计–>一个类只能创建一个对象,有效减少内存占用空间
设计一个系统—>百度 搜索引擎
public class Baidu{public void 搜索(String keyword){}}
创建一个Baidu对象 new
调用搜索的方法 , 做事情 , 方法执行一遍
问题:
同一时间有很多很多很多很多人在使用这个系统
解决方法:
对象—>只创建一个 , 堆内存中就只开辟一个空间
调用一次方法—>临时执行一次 方法执行空间就回收啦
五、存在继承关系的类 加载机制 及执行过程
父类:
package test;public class Animal {public String test = "AnimalField";public static String testStatic = "AnimalStaticField";public Animal(){System.out.println("我是animal中默认无参数的构造方法");}{this.test(); //块中调用了普通方法System.out.println("我是animal中的普通代码块"+test);}static{Animal.testStatic();System.out.println("我是animal中的静态代码块"+testStatic);}public void test(){System.out.println("我是animal类中的普通方法");}public static void testStatic(){System.out.println("我是animal类中的静态方法");}
}
子类:
package test;public class Person extends Animal{public String test = "personField";public static String testStatic = "personStaticField";public Person(){//super();//默认调用父类无参数的构造方法System.out.println("我是person中默认无参数的构造方法");}{this.testPerson(); //调用了普通方法System.out.println("我是person中的普通代码块"+test);}static{Person.testStatic();System.out.println("我是person中的静态代码块"+testStatic);}public void testPerson(){System.out.println("我是person类中的普通方法");}public static void testStatic(){System.out.println("我是person类中的静态方法");}
}
主方法:
package test;public class Test {public static void main(String[] args){//加载类的过程---静态元素已经加载new Person();//p.hashCode();//1.加载父类//2.父类会产生自己的静态空间 属性 方法 块// 执行静态块//3.加载子类//4.子类会产生自己的静态空间 属性 方法 块// 执行静态块//--------------------------------------------------//5.开辟对象空间//6.加载父类的非静态成员 属性 方法 块 构造方法//7. 执行块 执行父类构造方法//8.加载子类的非静态成员 属性 方法 块 构造方法//9. 执行块 执行子类构造方法//10.将对象空间的地址引用交给 变量来存储 Person p = new Person();}
}
先加载父类Animal模板,加载父类模板同时就加载了Animal静态元素空间。
然后加载子类Person,顺道直接加载了子类Person类的静态元素空间。
静态元素空间存放的是静态的属性,方法和块。
运行new Person()
的过程:
加载类的过程-----静态元素已经加载
先1.加载父类
2.父类会产生自己的静态空间 静态的属性 方法 块 执行块
执行静态块
3.加载子类
4.子类会产生自己的静态空间 静态的属性 方法 块 执行块
执行静态块
然后执行new Person()
,
5.开辟对象空间
6.加载父类的非静态成员 属性 方法 块 构造方法
7.执行块 执行父类构造方法
8.加载子类的非静态成员 属性 方法 块 构造方法
9.执行块 执行子类构造方法
10.将对象空间的地址引用交给 变量来存储
输出结果以及分析:
先1.加载父类
2.父类会产生自己的静态空间 静态的属性 方法 块 执行块
执行静态块
Aniaml静态块中调用了静态方法Animal.testStatic();
,所以先执行了静态方法,输出我是animal类中的静态方法,这也说明了:静态方法已经加载好了,在创建对象之前就加载好了,所以即使没有创建对象也可以调用。同时也说明静态方法是需要调用才会执行的,不是加载类就执行。除了构造函数以外的任何方法,都需要调用才可以执行。
然后继续执行静态块中的第二句:System.out.println("我是animal中的静态代码块"+testStatic);
输出:我是animal中的静态代码块AnimalStaticField
3.加载子类
4.子类会产生自己的静态空间 静态的属性 方法 块 执行块
执行静态块
Person类中的静态块,也是先调用了静态方法Person.testStatic();
,所以先输出我是person类中的静态方法。然后继续执行静态块中的第二句:System.out.println("我是person中的静态代码块"+testStatic);
输出:我是person中的静态代码块personStaticField
然后执行
new Person()
,
通过new,先5.开辟对象空间
6.加载父类的非静态成员 属性 方法 块 构造方法
7.执行块 执行父类构造方法 。先执行块,this.test(); //块中调用了普通方法
,输出:我是animal类中的普通方法。然后执行块中的第二句:System.out.println("我是animal中的普通代码块"+test);
输出我是animal中的普通代码块AnimalField。执行父类的构造方法:System.out.println("我是animal中默认无参数的构造方法");
输出:我是animal中默认无参数的构造方法
8.加载子类的非静态成员 属性 方法 块 构造方法
9.执行块 执行子类构造方法。 先执行块,块中调用了普通方法:this.testPerson(); //调用了普通方法
,所以输出:我是person类中的普通方法。然后执行块中的第二句,输出我是person中的普通代码块personField。最后执行构造方法,输出:我是person中默认无参数的构造方法
实际上默认执行的东西只有块和构造函数,其他的方法都必须被调用才能执行。还有一点指的注意的就是:静态的变量是在加载类的同时加载的,但是只是加载,并不会自动运行方法,只会自动运行块。
六、native
- Java源代码中看到native就已经再也看不见后续代码
- 后续会调用其他的编程语言C++ , C执行内存的操作 , 帮我们操作内存。
- Object类中一个方法:hashCode
七、abstract
abstract:抽象的—(很不具体 没有具体的执行 只是个概念)
例子:
基类:基类中的方法,只有一个结构,没有方法执行体。
package abstracttt;public abstract class Animal {//抽象方法public abstract void eat();//残次品
}
- 可以修饰什么
- 修饰方法
- 用abstract修饰符修饰的方法 只有方法的结构 没有方法执行体叫做抽象方法
- 当然注意native修饰的方法虽然也没有方法体 但是不是抽象方法 只是执行的过程是其他语言写的 看不见
- 修饰类
- 用abstract修饰符修饰的类 叫做抽象类
- 修饰后有什么特点
- 抽象类中必须有抽象方法么? 不是必须含有抽象方法
- 抽象方法必须放在抽象类中么? 目前来看必须放在抽象类中(或接口中) 普通类是不允许含有抽象方法。
- 研究一下什么叫抽象类 ,抽象类有什么特点?(通常用来描述事物 还不是很具体)。
刚才的Animal就是一个抽象类。
- 类里面有什么 成员
(1)属性:可以含有一般的属性 ,也可以含有 private static final等等
(2)方法:可以含有一般的方法 ,也可以含有 private static final等等
注意:抽象类中是允许含有抽象方法(只有方法结构,没有方法执行体)
(3)块:可以含有一般的程序块 也可以含有static程序块
(4)构造方法:可以含有构造方法, 包括重载,但是我们不能通过调用构造方法直接创建对象 - 类如何使用 创建对象
(1) 抽象类含有构造方法,但是我们不能通过调用构造方法直接创建对象
(2)抽象类只能通过子类单继承来做事
为什么不让我们调用构造方法创建对象?为什么还有呢? - 类和类的关系
抽象类----直接单继承----抽象类 可以
抽象类----直接单继承----具体类 可以 (用法通常不会出现)
具体类----直接单继承----抽象类 不可以直接继承 (将父类的抽象方法具体化 或子类也变成抽象类) - 小问题
(1)抽象类中能不能没有抽象方法,全部都是具体成员-----可以
(2)抽象类中能不能没有具体成员,全部都是抽象方法----- 可以 —> 抽象类抽象到极致 质的变化 —> 接口
(3)接口可以理解为是抽象类抽象到极致—>还是一个类的结构 不能用class修饰 改用interface修饰
八、接口
什么是接口(通常是为了定义规则)
- 接口也是一个类的结构 只不过 用interface修饰 替换原有的class
- 有什么 成员
属性: 不能含有一般属性,只能含有 公有的静态的常量 public static final
方法: 不能含有一般方法,只能含有 公有的抽象的方法(1.8 defualt修饰具体方法)
块: 不能含有一般程序块,也不能含有static块(块本身就是具体的,接口中不让有具体的)
构造方法:不能含有构造方法 - 如何使用 创建对象
不能创建对象
只能通过子类多实现(implements)来做事
public class A implements B,C,D{}
- 与别的类结构关系
接口不能继承别的类 最抽象
抽象类----直接多实现----接口 可以
具体类----直接多实现----接口 不可以直接 (必须将接口中的抽象方法具体化 或者 自己变成抽象类)
*接口—多继承—接口 可以直接多实现
接口的子类必须实现接口中全部的方法吗?答案:不是。原因如下:
如果子类是非抽象类,则必须实现接口中的所有方法;
如果子类是抽象类,则可以不实现接口中的所有方法,因为抽象类中允许有抽象方法的存在!
这篇关于java学习基础课之面向对象(渡一教育)【修饰符】(六)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!