3面向对象
面向对象
1 面向对象三条主线
Java类及类的成员:属性,方法,构造器;代码块,内部类
面向对象三大特性:封装性,继承性,多态性
其他关键字:this, super, static, final, abstract, interface, package, import
2 类,对象,属性,方法
类:是一类事物的描述,是抽象的概念上的定义
对象:是实际存在的该类事物的每个个体,也称为实例
属性:又叫成员变量,field,域,字段
方法:又叫成员方法,函数,method
3 属性
/*
类中属性的使用
属性(成员变量)vs局部变量
相同:
1定义变量格式一样
2先声明后使用
3都有其对应的作用域
不同:
1在类中声明位置不同:
属性:直接定义在类的{}
局部变量:声明在方法内,方法形参,代码块内,构造器形参,构造器内部的变量
2关于权限修饰符的不同:
属性:可以在声明属性时,指明其权限修饰符,public,private,protected,却省
局部变量:不可以使用权限修饰符
3默认初始化值的情况:
属性:根据其类型,有默认初始化值(整型:0 浮点型:0.0 字符型:0 布尔型: false 引用数据类型:null)
局部变量:没有默认初始化值,所以一定要显示赋值(特别的,方法形参还没有赋值时 可以没有初始化值)
4在内存中加载位置:
属性:加载到堆空间中(非STATIC)
局部变量:加载到栈空间
*/
public class Fao30LeiDingYi {
public static void main(String[] args){
//创建person类的对象
Person fao=new Person();
//Scanner scanner= new Scanner(System.in)
//调用对象的结构:属性,方法
//对象.方法
fao.name="fao";
fao.isMale=true;
System.out.println(fao.name);
//对象.方法
fao.eat();
fao.sleep();
fao.talk("中文");
System.out.println();
Person p2=new Person();
System.out.println(p2.name);//null 属性有默认初始化值
Person p3=fao;//将fao地址值赋给p3,导致p1p3指向了堆空间同一个对象实体
System.out.println(p3.name);//fao
}
}
class Person{
//属性(成员变量)
String name;
int age=22;
boolean isMale;
//方法
public void eat(){
System.out.println("人可以吃饭");
}
public void sleep(){
System.out.println("人可以睡觉");
}
//括号内就是局部变量
public void talk(String language){//局部变量
System.out.println("人可以说"+language);
}
}
4 方法
/*
1方法声明:权限修饰符 返回值类型 方法名(形参列表){
方法体
}
static final abstract后面再说
权限修饰符:private public protected 缺省
返回值类型:有返回值和无返回值
如果方法有返回值 必须在声明时指定返回值的类型 同时方法中需要使用 return关键字
如果没有返回值 就使用void 通常不用return 如果使用 只能“return;”表 示结束此方法
我们定义方法该不该有返回值?首先看题目要求;凭经验
方法名:属于标识符,遵循标识符的规则和规范 且见名知意
形参列表:可以声明0,1多个形参 格式:数据类型1 形参1,数据类型2 形参2...
方法体:方法功能的体现
return:使用在方法中
作用:结束一个方法+针对于有返回值类型的方法可以返回所要的数据
注意 return后面不可以声明执行语句
2方法使用:
可以调用当前类的属性,或方法
方法中不可以定义其他方法
*/
5 对象的内存解析



6 匿名对象
我们创建对象时,没有显示的赋给一个变量名
匿名对象只能调用一次
public class Fao35NiMingDuiXiang {
public static void main(String[] args){
Phone p=new Phone();
//匿名对象
new Phone().sendEmail();//发送邮件
new Phone().playGame();//玩游戏
PhoneMail mail=new PhoneMail();
mail.show(new Phone());//实际开发中匿名对象的使用
}
}
class PhoneMail{
public void show(Phone phone){
phone.sendEmail();
phone.playGame();
}
}
class Phone{
double price;
public void sendEmail(){
System.out.println("发送邮件");
}
public void playGame(){
System.out.println("玩游戏");
}
}
7 方法的重载
在同一个类中 允许一个以上同名方法 只要参数个数或参数类型不同
"两同一不同":同一个类 相同方法名 参数列表不同(个数不同 类型不同)
判断是否重载:
和方法权限修饰符,返回值类型,形成变量名,方法体都没有关系
在通过对象调用方法时:如何确定某一个指定的方法
方法名-->参数列表
public class Fao37FangFaOverload {
public static void main(String[] args){
OverLoadTest test=new OverLoadTest();
test.getSum(1,2);//第一个
test.getSum(1.1,2);//第二个
}
}
class OverLoadTest{
public void getSum(int i,int j){
System.out.println(i+j);
}
public void getSum(double i,double j){
System.out.println(i+j);
}
// public int getSum(int i,int j){ 这个不构成重载
// System.out.println(i+j);
// }
}
8 可变个数形参
- jdk5.0新增的内容: 数据类型...变量名
- 当调用可变个数形参方法时 传入参数个数可以是0,1,2...
- 可变个数形参方法和本类中方法名相同,形参不同的方法之间构成重载
- 可变个数形参方法和本类中方法名相同,形参类型也相同的数组方法之间不构成重载
- 可变个数形参在方法的形参列表中必须声明在末尾
- 可变个数形参在方法的形参列表中最多只能声明一个
public class Fao38KeBianXingCan {
public static void main(String[] args){
KeBian test=new KeBian();
test.show(12);
test.show("hello");
test.show("fao","hello");
}
}
class KeBian{
public void show(int i){
System.out.println(i);
}
public void show(String s){
System.out.println(s);
}
public void show(String...strs){
System.out.println("lala");
for(int i=0;i<strs.length;i++){
System.out.println(strs[i]);
}
}
// public void show(String[] strs){ 和上面是一样 这是以前旧版本
//
// }
public void show(int i,String...strs){//必须最后一个 且只能有一个
System.out.println("lala");
}
}
9 值传递机制
关于变量的赋值:
如果变量是基本数据类型,此时赋值的是变量所保存的数据值
如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值
方法形参的传递机制:值传递
形参:方法定义时小括号内的参数
实参:调用方法时实际给形参传递的值
值传递机制:
如果变量是基本数据类型,此时实参赋值给形参的是实参所保存的数据值
如果变量是引用数据类型,此时实参赋值给形参的是实参所保存的数据的地址值
public class Fao39ZhiChuanDi {
public static void main(String[] args){
//交换两个变量的值的操作
int m=10;
int n=20;
System.out.println("m: "+m+" n: "+n);//m: 10 n: 20
//int temp=m;
//m=n;
//n=temp;
//System.out.println("m: "+m+" n: "+n);//m: 20 n: 10
TestSwap test=new TestSwap();
test.swap(m,n);
System.out.println("m: " + m + " n: " + n);//m: 10 n: 20 没变
Data data=new Data();
data.m=10;
data.n=20;
test.swap2(data);
System.out.println("m: " + data.m + " n: " + data.n);//m: 20 n: 10
}
}
class TestSwap {
public void swap(int m, int n) {
int temp = m;
m = n;
n = temp;
}
public void swap2(Data data) {
int temp = data.m;
data.m = data.n;
data.n = temp;
}
}
class Data{
int m;
int n;
}
10 递归
一个方法体内自己调用自己
方法递归包含隐式循环
递归一定要向已知方向递归,否则就变成了无穷递归
11 面向对象特征一:封装与隐藏
11.1为什么要封装与隐藏
- 当我们创建一个类的对象以后,我们可以通过对象.属性的方式 对属性进行赋值 这破坏了封装性
- 且实际条件中 往往要给属性加多个限制条件 我们只能通过方法来进行条件的添加
- 同时我们需要避免用户再使用对象.属性的方式再进行赋值,因此需要将属性设置为private
11.2封装性的体现
- 我们将类的属性私有化 再提供公共的方法来获取(get...)和设置(set...)
11.3权限修饰符
- java规定了四种权限(从小到大)private 却省 protected public
- 这四种权限可以用来修饰类及类的内部结构:属性 方法 构造器 内部类
- 具体的: 4种权限都可以用来修饰类及类的内部结构:属性 方法 构造器 内部类
修饰类的话 只能使用:却省 public - 却省出了不同包就不能使用了

12 构造器
构造器的作用
- 创建对象
- 初始化对象的属性
说明
- 如果没有显示定义构造器 系统会定义一个空的构造器
- 定义构造器的格式: 权限修饰符 类名(形参列表)
- 一旦我们显示定义了类的构造器以后,系统就不在提供默认的空参构造器
- 一个类中,至少要有一个构造器
属性赋值的先后顺序(具体看25)
- 默认初始化
- 显式初始化
- 构造器初始化
- 通过 对象.方法 或 对象.属性 赋值
public class Fao43GouZaoQi {
public static void main(String[] args){
//创建类的对象:new+构造器
Person p1=new Person();
p1.eat();
Person p2=new Person("fao",22);
p2.eat();
}
}
class Person{
//属性
String name;
int age;
//构造器
public Person(){
}
public Person(String n, int i){
name=n;
age=i;
}
//方法
public void eat(){
System.out.println("人吃饭");
}
public void study(){
System.out.println("人可以学习");
}
}
13 this关键字
this关键字使用
- 可以用来修饰:属性,方法,构造器
this属性和方法
- this理解为:当前对象
- 在类的方法中,我们可以使用“this.属性”或“this.方法”方式来调用当前对象的属性或方法
- 但通常情况下我们都选择省略this.
- 特殊情况下,如果方法的形参的类的属性同名时 我们必须显示的使用this.变量 表示此变量是属性而非形参
this构造器
- 我们在类的构造器中可以显示使用“this(形参列表)"方式来调用指定本类中指定的其他构造器
- 构造器中不能通过上述方式调用自己
- 如果一个类中有n个构造器 则最多有n-1个构造器使用上述
- 规定:this(形参列表)格式必须用在当前构造器的首行
- 构造器内部只能使用一个上述形式
class person2{
private String name;
private int age;
public person2(){
//假设里面有好多行初始代码
}
public person2(String name){
this();
this.name=name;
}
public person2(String name,int age){
this(name);
this.age=age;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
public void eat(){
System.out.println("人吃饭");
study();//省略了this.study
}
public void study(){
System.out.println("人学习");
}
}
14 package和import关键字
package关键字使用:
- 为了更好实现项目中类的管理 提供包的概念
- 使用package声明类或接口所属的包,写在源文件的首行
- 包属于标识符 需要遵循标识符的命名规则规范(xxyyzz) “见名知意”
- 每.一次 就代表一层文件目录
- 补充:同一个包下 不能命名同名的接口,类;不同包下可以命名
import关键字使用:
- import:导入
- 在源文件中 显示使用import结构导入指定包下的类,接口
- 声明在包的声明和类的声明之间
- 如果需要导入多个结构 则并列写出即可
- 可以使用xxx.*方式 表示可以导入xxx包下的所有结构
- 如果使用的类或接口是java.lang包下定义的,则可以省略import结构
- 如果调用的是当前包下定义的,也可以省略import
- 如果在源文件中 使用了不同包下的同名类则必须至少有一个类需要以全类名的方式来命名
- 如果我们使用xxx.*形式可以调用xxx包下所有结构 但如果使用xxx包下子包的结构 则仍需要重新导 直接看成两个不同的包
- import static:导入指定类或接口中静态结构:属性或者方法
15 面向对象特征二:继承性
15.1继承性的好处
- 减少了代码的冗余 提高了代码的复用性
- 便于功能的扩展
- 为之后的多态性的使用 提供了前提
15.2继承性的使用
- class A extends B{}
- A:子类 派生类 subclass
- B:父类 超类 基类 superclass
- 体现 一旦子类A继承父类B以后 A就获取了B中声明的结构:属性,方法
- 特别的父类中声明为private的属性或方法,子类继承父类以后 仍然获取了父类的结构
- 只是因为封装性的影响,使得子类不能直接调用父类的结构而已
- 子类继承父类以后 还可以定义自己特有的属性和方法 实现功能的拓展
15.3 继承性的规定
- 一个类可以被多个子类继承
- 一个类只能有一个父类:java中类的单继承性
- 子类直接继承的父类叫直接父类 间接继承的叫间接父类
- 子类继承父类之后 就获取了直接父类和间接父类的结构:属性和方法
- 如果我们没有显示声明一个类的父类的话 则此类继承与java.lang.Object类
- 所有的java类都直接或间接继承与Object类(除了它自己)
- 意味着所有java类都具有Object中声明的功能
15.4 方法重写
- 重写:子类继承父类以后,可以对父类中声明的方法进行覆盖操作
- 应用:重写以后,当创建子类对象以后,通过子类对象调用父类中同名同参数的方法时,实际执行的是子类重写父类的方法
- 方法声明:权限修饰符 返回值类型 方法名(形参列表)throws 异常的类型
- 子类中叫重写的方法,父类中叫被重写的方法
- 重写方法的方法名和形参列表和父类被重写的相同
- 重写的方法的权限修饰符不小于父类的被重写的修饰符(特殊情况:子类不能重写父类中声明为private的方法)
- 返回值类型:a. 如果父类返回值是void 则子类重写方法返回值也只能是void
b. 父类被重写的方法返回值类型是A类型 则子类重写方法返回值类型可以是A类或A类的子类
c. 父类被重写的方法返回值类型是基本数据类型,则子类重写方法返回值类型必须是相同的基本数据类型 - 子类和父类中同名同参数的方法要么都声明非static(考虑重写),要么都声明为static(不叫重写)
15.5 子类权限
- 同一个包中其他类 不可以调用私有属性和方法
- 不同包下普通类(非子类) 要使用父类不能调用声明为private protected 却省的属性或方法
- 在不同包的子类中,不能调用父类中声明为private和缺省的属性或方法
16 super关键字使用
super解释为:父类的
super可以用来调用:属性,方法,构造器
super使用:调用属性和方法
- 我们可以在子类的方法或构造器中,通过使用super.属性或super.方法方式来显示调用父类中声明的属性或方法, 但是通常情况下我们习惯省略super.
- 特殊情况1:当子类和父类定义了同名属性时,我们要想在子类中调用父类中声明的属性,则必须显示使用super.属性的方式 表名调用的父类中声明的属性
- 特殊情况2:当子类重写了父类方法之后,我们想在子类的方法中调用父类中被重写的方法时使用super.方法表明调用的是父类中被重写的方法
super调用构造器
- 可以在子类构造器中显示使用“super(形参列表)”的方式,调用父类中声明的指导构造器
- super(形参列表)的使用,必须声明在子类构造器的首行
- 我们在类的构造器中,针对于this(形参列表)或super(形参列表)只能出现一种
- 当构造器首行没有显示声明this或super则默认调用父类中空参构造器即super()
- 在类的多个构造器中,至少有一个类的构造器中使用了super(形参列表)
public class Fao53Super {
public static void main(String[] args){
Student s=new Student();
s.show();//2
s.study();
Student s1=new Student("tom",21,"it");
s1.show();
}
}
class Person{
String name;
int age;
int id=1;//身份证号
public Person(){
}
public Person(String name, int age){
this.name=name;
this.age=age;
}
public void eat(){
System.out.println("人吃饭");
}
public void walk(){
System.out.println("人走路,走的距离是:");
}
}
class Student extends Person{
String major;
int id=2;//学号 内存中有两个Id 属性不会覆盖
public Student(){
}
public Student(String major){
this.major=major;
}
public Student(String name,int age,String major){
super(name,age);//调用父类的构造器
this.major=major;
}
public void study(){
System.out.println("学习,专业是:"+major);
eat();//默认this.eat()
super.eat();
}
//对父类中eat方法进行重写
public void eat(){
System.out.println("学生多吃有营养的事物");
}
public void show(){
System.out.println("name= "+name+" age= "+age);
System.out.println("id= "+id);//省略this.id
System.out.println("父类id= "+super.id);
}
}
17 子类对象实例化
从结果上来看
- 子类继承父类以后,就获取了父类中声明的属性或方法
- 创建子类的对象,在堆空间中,就会加载所有父类中声明的属性
从过程上来看
- 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器
- 进而调用父类的父类的构造器 直到java.lang.Object类中空参的构造器为止
- 正因为加载过所有父类的结构,才可以在看到内存中有所有父类中的结构 子类对象才可以考虑进行调用
明确
- 虽然创建子类对象时,调用了父类的构造器 但至始至终就创建了一个对象
18 面向对象特征三:多态性
18.1何谓多态性
- 对象的多态性:父类的引用指向子类的对象(或者子类的对象赋给父类的引用)
18.2 多态的使用:虚拟方法调用
- 有了对象的多态性以后,我们在编译期只能调用父类中声明的方法,但运行期,实际执行的是子类重写父类的方法
- 总结:编译看左边,执行看右边
- 虚拟方法调用:子类中定义了与父类同名同参数的方法,在多态的情况下,将此时父类的方法称为虚拟方法,父类根据给它的不同子类对象,动态调用属于子类的该方法,这样的方法调用在编译期是无法确定
- 动态绑定:Person e=new Student(); 编译时e为Person类型,而方法的调用是在运行时确定的,所有调用的是Student类的方法
18.3 多态性使用前提
- 要有类的继承关系
- 方法的重写
- 对象的多态性:只适用于方法,不适用于属性
public class Fao55DuoTaiXing {
public static void main(String[] args){
// Person p1=new Person();
// p1.eat();
//
// Man man=new Man();
// man.eat();
//对象的多态性:父类的引用指向子类的对象
Person p2=new Man();
//多态的使用:当调用父类同同参数方法时,实际执行的是子类重写父类的方法--虚拟方法调用
p2.eat();
p2.walk();
System.out.println(p2.id);//属性没有多态性1
//不能调p2.earnMoney();
//不能调用p2.isSmoking
//有了对象多态性以后,内存上实际是加载了子类特有的属性和方法的
//由于变量声明为父类类型 导致编译时只能调用父类中声明的属性和方法 不能调子类的
//如何才能调用子类特有的属性和方法? 使用强制类型转换符(向下转型)
Man m1=(Man) p2;
m1.earnMoney();
m1.isSmoking=true;
//使用强转时,有可能有异常 ClassCastException
//Woman w1=(Woman) p2;
//w1.goShopping();异常
Person p3=new Woman();
//引入instanceof:
//关键字使用 a instanceof A:判断对象a是否是A的实例,如果是,返回true
//未来避免在向下转型时出现异常 所以先进行instanceof判断
if(p2 instanceof Woman){
System.out.println("woman");
}
if(p2 instanceof Man){
System.out.println("man");
}
//如果B是A的父类 且a instanceof A为true 则a instanceof B也肯定为true
}
}
class Person{
String name;
int age;
int id=1;
public Person(){
}
public Person(String name, int age){
this.name=name;
this.age=age;
}
public void eat(){
System.out.println("吃饭");
}
public void walk(){
System.out.println("走路,走的距离是:");
}
}
class Man extends Person{
int id=2;
boolean isSmoking;
public void earnMoney(){
System.out.println("男人负责挣钱养家");
}
public void eat(){
System.out.println("男人多吃肉");
}
public void walk(){
System.out.println("男人霸气走路");
}
}
class Woman extends Person{
boolean isBeauty;
public void goShopping(){
System.out.println("女人喜欢购物");
}
public void eat(){
System.out.println("少吃,为了减肥");
}
public void walk(){
System.out.println("女儿窈窕的走路");
}
}
19 Object类
- Object类是所有java类的根父亲
- Object类中的功能(属性和方法)具有通用性
- object类只声明一个空参构造器
- 属性:无
- 方法(重点关注):equals()/toString()/getClass()/hashCode()/clone()/finalize()
20 equals和==,tostring的使用
tostring()
- 当我们输出一个对象的引用时,实际上就是调用当前对象的toString()
- return getClass().getName+"@"+Integer.toHexString(HasCode())
- 像String,Date File包装类都重写了toString()方法
- 使得在调用对象toString()时放回了实体内容信息
- 自定义类也可以重写toString()方法,当调用此方法时,返回实体内容
==的使用
- 可以使用基本数据类型变量和引用数据类型变量中
- 如果比较的是基本数据类型变量,比较的两个变量保存的数据是否相等
- 如果保存的引用数据类型变量,比较的是两个对象地址值是否相同
- 必须保证符号左右两边变量类型一致
equals()方法使用
- 是一个方法而非运算符
- 基本数据类型不能使用equals()
- Object类中equals()定义:和我们==的作用是相同的 比较地址值是否相同
- 像String,Date,File,包装类都重写了Object类中equals()方法,重写后都不载比较地址是否相同,而是比较两个对象“实体内容”是否相同
- 通常情况下,我们自定义的类如果使用equals()的话,也通常比较两个类实体内容是否相同,需要重写
- 重写规则:比较两个对象的实体内容是否相同
public class Fao60EqualsCeShi {
public static void main(String[] args){
int i=10;
int j=10;
double d=10.0;
System.out.println(i==d);//true 除了boolean类型
char c=10;
System.out.println(i==c);//true
Customer c1=new Customer("fao",22);
Customer c2=new Customer("fao",22);
System.out.println(c1==c2);//false
System.out.println(c1.equals(c2));//false重写后变成true
String s1="lala";
String s2="lala";
System.out.println(s1.equals(s2));//true
}
}
class Customer{
String name;
int age;
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
//手动实现
// public boolean equals(Object obj){
// if(this==obj){
// return true;
// }
// if(obj instanceof Customer){
// Customer cust=(Customer) obj;
// //比较两个对象每个属性是否相同
// if(this.age==cust.age && this.name.equals(cust.name)){
// return true;
// }
// }
// return false;
// }
//直接调用
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Customer customer = (Customer) o;
return age == customer.age && name.equals(customer.name);
}
//手动重写toString()
// public String toString(){
// return "Customer[name="+name+",age="+age+"]";
// }
@Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Fao61ToString {
public static void main(String[] args){
Customer cust1=new Customer("fao",21);
System.out.println(cust1.toString());//bilifao9.Customer@776ec8df
System.out.println(cust1);//重写后Customer[name=fao,age=21]
String str=new String("MM");
System.out.println(str);//MM
Date date=new Date(323223);
System.out.println(date.toString());//Thu Jan 01 08:05:23 CST 1970
}
}
21 八个包装类
-
JAVA提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征
-
掌握的:基本数据类型,包装类,String三者之间的相互转换
基本数据类 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
boolean Boolean
char Character
-
基本数据类型--包装类:调用包装类的构造器
-
包装类--基本数据类型:调用包装类的xxxValue()
-
上面两者改进,JDK5.0新特性:自动装箱与拆箱
-
基本数据类型,包装类--String类型:调用String重载的valueOf(xxx xxx)
-
String类型--基本数据类型,包装类 调用包装类的parseXxx()

public class Fao63BaoZhuangLei {
//基本数据类型--包装类:调用包装类的构造器
@Test
public void test1(){
int num1=10;
Integer in1=new Integer(num1);
System.out.println(in1.toString());//10
Integer in2=new Integer("123");
System.out.println(in2.toString());//123
Boolean b1=new Boolean(true);
Boolean b2=new Boolean("true");//忽略大小写 只要和true张的一样就行
Boolean b3=new Boolean("lal");//除了和true一样的其他全是false
}
//包装类--基本数据类型:调用包装类的xxxValue()
@Test
public void test2(){
Integer in1=new Integer(12);
int i1=in1.intValue();
System.out.println(i1+1);
Float fn1=new Float(12.1);
float f1=fn1.floatValue();
System.out.println(f1+1);
}
//JDK5.0新特性:自动装箱与拆箱
public void method(Object obj){
System.out.println(obj);
}
@Test
public void test3(){
int num1=10;
method(num1);//10自动装箱的体现
int num2=10;
Integer in1=num2;//自动装箱
System.out.println(in1.toString());//10
int num3=in1;//自动拆箱
System.out.println(num3+1);//1
}
//基本数据类型,包装类--String类型:调用String重载的valueOf(xxx xxx)
@Test
public void test4(){
int num1=10;
//方式1:连接运算
String str1=num1+"";
//方式2
float f1=12.3f;
String str2=String.valueOf(f1);
Double d1=new Double(12.4);
String str3=String.valueOf(d1);
System.out.println(str2);//12.3
System.out.println(str3);//12.4
}
//String类型--基本数据类型,包装类 调用包装类的parseXxx()
@Test
public void test5(){
String str1="123";
//int num1=(int)str1不行
//可能会报NumberFormatException
int num2=Integer.parseInt(str1);
System.out.println(num2+1);//124
String str2="true1";
boolean b1=Boolean.parseBoolean(str2);
System.out.println(b1);//false
}
}
22 static
概述
- static:静态的
- static:可以用来修饰:属性,方法,代码块,内部类
static修饰属性:静态变量(类变量)
- 属性,按是否使用static修饰,分为静态属性和非静态属性(实例属性)
- 实例变量:我们创建了类的多个对象,每个对象都独立拥有一套类中非静态属性,当修改其中一个对象非静态属性时,不会导致其他对象的非静态属性修改
- 静态变量:我们创建了类的多个对象,每个对象共用静态属性,当修改其中一个对象静态属性时,会导致其他对象调用此静变量是修改过的
- 静态变量随着类的加载而加载,可以通过类.方式调用,静态变量加载要早于对象的创建, 由于类只会加载一次,所以静态变量在内存中也只会存在一份,存在方法区的静态域中
- 静态属性举例:System.out Math.PI
- 类变量 实例变量
类 yes no
对象 yes yes
static修饰方法:静态方法
- 随着类的加载而加载,可以通过类.方法的方式进行调用
- 静态方法中只能调用静态的方法或属性
- 非静态方法中,既可以调用非静态的属性或方法,也可以调用静态的属性或方法
- 静态方法 非静态方法
类 yes no
对象 yes yes
static注意点
- 在静态方法内,不能使用this关键字,super关键字
- 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解
- 开发中如何确定一个属性是否声明为static?属性可以被多个对象所共享的,不会随着对象的不同而不同
- 开发中如何确定一个方法是否声明为static?操作静态属性的方法通常设置为静态的;工具类中的方法习惯上都声明为static的,比如Math Array Collections
public class Fao65Static {
public static void main(String[] args){
Chinese c1=new Chinese();
c1.name="范翱";
c1.age=40;
Chinese c2=new Chinese();
c2.name="啦啦";
c2.age=30;
c1.nation="CHN";
System.out.println(c2.nation);//CHN
Chinese.nation="CHINESE";
Chinese.show();//我是中国人
c1.eat();//中国人吃早餐 我是中国人
}
}
class Chinese{
String name;
int age;
static String nation;
public void eat(){
System.out.println("中国人吃早餐");
show();
}
public static void show(){
System.out.println("我是中国人");
}
}
23 main()
- main()方法作为程序的入口
- main()方法也是一个普通的静态方法
- main()方法也可以作为我们与控制台交互的方式(之前使用Scanner)
public class Fao69MainLiJie {
public static void main(String[] args){
Main.main(new String[100]);
for (int i=0;i<args.length;i++){
System.out.println("*****"+args[i]);
}
}
}
class Main{
public static void main(String[] args){
args=new String[100];
for (int i=0;i<args.length;i++){
args[i]="args_"+i;
System.out.println(args[i]);
}
}
}
24 代码块
代码块简介
- 代码块的作用:用来初始化类,对象
- 代码块如果有修饰的话,只能使用static
- 分类:静态代码块和非静态代码块
静态代码块
- 内部可以有输出语句
- 随着类的加载而执行,而且只执行一次
- 作用:初始化类的信息
- 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
- 静态代码块执行要优先于非静态代码块
- 静态代码块内只能调用静态属性和方法,不能调用非静态结构
非静态代码块
- 内部可以有输出语句
- 随着对象的创建而执行,而且每创建一个对象就执行一次非静态代码块
- 作用:可以在创建对象时,对对象的属性进行初始化
- 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
- 非静态代码块可以调用静态的属性,静态的方法以及非静态的结构
public class Fao70Block {
public static void main(String[] args){
String desc=Person.desc;//hello, static block
Person p1=new Person();//hello,block
Person p2=new Person();//hello,block
System.out.println(p1.age);//1
System.out.println(desc);//我是一个爱学习的人
}
}
class Person{
//属性
String name;
int age;
static String desc="我是一个人";
//构造器
public Person(){
}
public Person(String name, int age){
this.name=name;
this.age=age;
}
//代码块
static{//静态代码块
System.out.println("hello, static block");
desc="我是一个爱学习的人";
}
{//非静态代码块
System.out.println("hello,block");
age=1;
}
//方法
public void eat(){
System.out.println("吃饭");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", desc='" + desc + '\'' +
'}';
}
public static void info(){
System.out.println("我是一个快乐的人");
}
}
25 属性赋值顺序
- 1默认初始化
- 2显式初始化
- 3构造器中初始化
- 4有了对象以后,对象.属性或者对象.方法进行赋值
- 5在代码块中赋值
执行的先后顺序:1-2/5-3-4
public class Fao71OrderTest {
public static void main(String[] args){
Order order=new Order();
System.out.println(order.orderId);//4
}
}
class Order{
int orderId=3;
{//写上面就变成3了 谁先写谁先执行 通常代码块在后面写
orderId=4;
}
}
26 final
final简介
- final:最终的
- final可以用来修饰的结构:类,方法,变量
final修饰的类
- 此类不能被其他类所继承
- 比如String类,System类,StringBuffer类
final修饰的方法
- 表示此方法不可以被重写
- 比如 object类中的getClass()
final修饰的变量
- 此时的“变量”称为是一个常量
- final修饰属性:可以考虑赋值的位置有:显示初始化,代码块中初始化,构造器中初始化(方法中不能初始化)
- final修饰局部变量:尤其是使用final修饰形参时,表明此形参是一个常量,当我们调用此方法时,给常量形参赋一个实参;一旦赋值以后,就只能在方法体内使用此形参,但不能重新赋值
final static用来修饰:属性,方法(不常用)
- 修饰属性:全局常量
public class Fao72FinalTest {
final int WIDTH=10;//此时就变成常量了 显示初始化
final int LEFT;
final int RIGHT;
// final int DOWN;
{
LEFT=1;//代码块中初始化
}
public Fao72FinalTest(){
RIGHT=2;//构造器中初始化
}
//通过方法初始化不可行
//因为可能没调用这个方法
// public void setDOWN(int down){
// this.DOWN=down;
// }
public void show(){
final int NUM=10;//变成常量
}
public void show(final int num){
// num=20;编译不通过
System.out.println(num);
}
public static void main(String[] args){
Fao72FinalTest test=new Fao72FinalTest();
test.show(10);
}
}
//final修饰的类 不能被继承
final class FinalA{
}
27 abstract
abstract简介
- abstract:抽象的
- 可以用来修饰结构:类,方法
abstract修饰类:抽象类
- 此类不能实例化
- 抽象类中一定有构造器,便于子类实例化时调用
- 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关操作
abstract修饰方法:抽象方法
- 只有方法的声明,没有方法体
- 包含抽象方法的类一定是抽象类,反之抽象类中可以没有抽象方法
- 若子类重写了父类中的所有抽象方法后,此子类可实例化
- 若子类没有重写了父类中的所有抽象方法,则此子类也是一个抽象类,需要用abstract
使用注意点:
- abstract不能用来修饰属性,构造器,代码块等结构
- abstract不能用来修饰私有方法,静态方法,final的方法,final的类
public class Fao73Abstract {
public static void main(String[] args) {
//一旦抽象了 就不可实例化
// Person p1=new Person();
// p1.eat();
}
}
abstract class Person{
String name;
int age;
public Person(){
}
public Person(String name, int age){
this.name=name;
this.age=age;
}
//抽象方法
public abstract void eat();
public void walk(){
System.out.println("人走路");
}
}
class Student extends Person{
public Student() {
}
public Student(String name, int age){
super(name,age);
}
//必须重写或者再定义为抽象类
public void eat(){
System.out.println("学生应该多吃事物");
}
}
抽象类的匿名子类
public class Fao74NiMingZiLei {
public static void method(Person p){}
public static void main(String[] args){
method(new Student());//匿名对象
//创建抽象类的匿名类
method(new Person() {
@Override
public void eat() {
System.out.println("吃好东西");
}
});
}
}
抽象类的应用:模块方法的设计模式
public class Fao75TemplateTest {
public static void main(String[] args) {
Template t=new SubTemplate();
t.spendTime();
}
}
abstract class Template{
//计算某段代码执行所花费的时间
public void spendTime(){
long start=System.currentTimeMillis();
code();//不确定的部分,易变的部分
long end=System.currentTimeMillis();
System.out.println("花费时间为:"+(end-start));
}
public abstract void code();
}
class SubTemplate extends Template{
public void code(){
for (int i=2;i<=1000;i++){
boolean isFlag=true;
for (int j=2;j<=Math.sqrt(i);j++){
if(i%j==0){
isFlag=false;
break;
}
}
if (isFlag){
System.out.println(i);
}
}
}
}
28 接口
接口的简介:
- 接口使用interface来定义
- java中 接口和类是并列的两个结构
如何定义接口:接口中的成员
-
JDK7及以前:只能定义全局常量和抽象方法;
全局常量:public static final的 但书写时可以省略不写 但还是在
抽象方法:abstract
-
JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法和默认方法
-
接口中不能定义构造器!意味着接口不可以实例化
接口的使用:
- JAVA开发中,接口都通过让类去实现(implements)的方法来使用
- 如果实现类覆盖了接口中的所有抽象方法,则此实现类可以实例化
- 如果实现类没有覆盖接口中的所有抽象方法,则此实现类仍然是一个抽象类
- JAVA类可以实现多个接口--->弥补了JAVA单继承性的局限性,格式 class AA extends BB implements CC,DD,EE
- 接口与接口之间可以继承,而且可以多继承
//接口一
interface Flyable{
//全局常量
public static final int MAX_SPEED=7900;//第一宇宙速度
int MIN_SPEED=1;//省略了
//抽象方法
public abstract void fly();
void stop();//省略了
}
//接口二
interface Attackable{
void attack();
}
//实现接口的类
class Plane implements Flyable{
@Override//这里一般不叫重写 叫实现
public void fly() {
System.out.println("飞");
}
@Override
public void stop() {
System.out.println("停");
}
}
//接口继承同时使用
class Bullet extends Object implements Flyable,Attackable{
@Override
public void fly() {
}
@Override
public void stop() {
}
@Override
public void attack() {
}
}
interface AA{
}
interface BB{
}
//接口可以多继承接口
interface CC extends AA,BB{
}
接口的多态性体现
- 体现了一种规范
- 开发中体会面向接口编程
public class Fao78USBJuLi {
public static void main(String[] args) {
computer com=new computer();
//1创建了接口的非匿名实现类的非匿名对象
Flash flash=new Flash();
com.transferData(flash);
//2创建接口的非匿名实现类的匿名对象
com.transferData(new Flash());
//3创建接口的匿名实现类的非匿名对象
USB phone =new USB() {
@Override
public void start() {
System.out.println("手机");
}
@Override
public void stop() {
System.out.println("手机");
}
};
com.transferData(phone);
//4创建了接口的匿名实现类的匿名对象
com.transferData(new USB() {
@Override
public void start() {
System.out.println("4");
}
@Override
public void stop() {
System.out.println("4");
}
});
}
}
interface USB{
void start();
void stop();
}
class computer{
public void transferData(USB usb){
usb.start();
usb.stop();
}
}
class Flash implements USB{
@Override
public void start() {
System.out.println("FLASH");
}
@Override
public void stop() {
System.out.println("FLASH");
}
}
jdk8之后的接口:静态方法和默认方法
- JDK8之后除了定义全局常量和抽象方法之外,还可以定义静态方法,默认方法
- 接口中定义的静态方法,只能通过接口来调用
- 通过实现类的对象,可以调用接口中的默认方法,如果实现类重写了接口中的默认方法,调用时仍然是重写后的方法
public class Fao81Java8JieKou {
public static void main(String[] args) {
SubClass s=new SubClass();
//接口中定义的静态方法,只能通过接口来调用
CompareA.method1();//CompareA1
//通过实现类的对象,可以调用接口中的默认方法
s.method2();//SubClass
//如果子类或实现类继承的父类和实现的接口中声明了同名同参数的方法
//那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法,叫类优先原则
s.method3();//SuperClass
//如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法
//那么在实现类没有重写此方法的情况下,会报错--接口冲突
//需要我们必须在实现类中重写此方法
}
}
class SubClass extends SuperClass implements CompareA,CompareB{
public void method2(){
System.out.println("SubClass");
}
public void method(){
//如何在子类(实现类)方法中调用父类,接口中被重写的方法
method2();//调用自己重写的方法
super.method3();//调用父类中声明的方法
CompareA.super.method3();//调用接口中默认方法
}
}
class SuperClass {
public void method3(){
System.out.println("SuperClass");
}
}
//接口一
interface CompareA{
//静态方法
public static void method1(){
System.out.println("CompareA1");
}
//默认方法
public default void method2(){//可以省略public
System.out.println("compareA2");
}
public default void method3(){//可以省略public
System.out.println("compareA3");
}
public default void method4(){//可以省略public
System.out.println("compareA4");
}
}
interface CompareB{
// public default void method4(){
// System.out.println("compareB4");
// }
}
抽象类和接口有哪些共同点和区别
- 相同点:不能实例化,都可以被继承
- 不同点:抽象类:有构造器。 接口:不能声明构造器;多继承vs 单继承
29 内部类
简介:
- JAVA中允许将一个类A声明在另一个类B中,则类A就是内部类,类B就是外部类
- 内部类的分类:成员内部类(静态和非静态的)vs局部内部类(方法内,代码块内,构造器内),局部内部类开发中较少使用
成员内部类:
一方面作为外部类的成员
- 调用外部类的结构
- 可以通static修饰
- 可以被四种不同权限修饰
另一方面,作为一个类
- 类内可以定义属性,方法,构造器,内部类等
- 可以被final修饰,表示此类不能被继承 ; 不是final就可以被继承
- 可以被abstract修饰,表明此类不能被实例化
注意点
- 如何实例化成员内部类的对象
- 如何在成员内部类中去区分调用外部类的结构
- 开发中局部内部类的使用
- 在局部内部类的方法中,如果调用局部内部类所声明的方法的局部变量,要求此局部变量声明为final的(JDK8以后自动)(JDK7之前必须声明final)
总结
- 成员内部类和局部内部类,在编译以后,都会生成字节码文件
- 格式:成员内部类:外部类$内部类名.class;局部内部类:外部类$数字内部类名.class
public class Fao82InnerClass {
public static void main(String[] args) {
//创建dog实例(静态内部类)
Person.Dog dog=new Person.Dog();
dog.shout();//汪汪
//创建Bird实例(非静态内部类)
Person p=new Person();
Person.Bird bird=p.new Bird();//这边特殊
bird.sing();//我是一只小小鸟 人吃饭
System.out.println();
bird.display("waibu");//waibu bird PERSON
}
}
class Person{
String name="PERSON";
int age;
public void eat(){
System.out.println("人吃饭");
}
//静态成员内部类
static class Dog{
String name;
int age;
public void shout(){
System.out.println("汪汪");
}
}
//非静态成员内部类
class Bird{
String name="bird";
public void sing(){
System.out.println("我是一只小小鸟");
eat();//省略了Person.this.eat();
}
public void display(String name){
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性
}
}
public Person(){
//局部内部类
class CC{
}
}
public void method(){
//局部内部类
class AA{
}
}
{
//局部内部类
class BB{
}
}
}

浙公网安备 33010602011771号