多态性
- 理解多态性:可以理解为一个事物的多种形态。(运行时行为)
- 何为多态性:
(或子类的对象赋给父类的引用)
- 多态的使用:à虚拟方法调用
有了对象的多态性以后,我们在编译期,只能调用父类的方法,但在运行期间,我们实际执行的是子类重写父类的方法。
总结:编译,看左边;运行,看右边
- 多态性的使用前提:①类的继承关系 ②要有方法的重写
5.对象的多态性:只适用于方法,不适用于属性(编译和运行都看左边)
instanceof关键字的使用
a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。
使用情景:为了向下转型时出现ClassCastException的异常,我们在向下转型前,先进行instanceof的判断,一旦返回true,就进行向下转型;如果返回false,不进行向下转型。
如果 a instanceof A返回true,则a instanceof B也返回true
其中类B是类A的父类
Object类的使用
- Obiect类是所有Java类的根父类
- 如果再类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
- Object类中的功能(属性、方法)就具有通用性。
属性:无
方法:equals()/toString()/getClass()/hashCode()/clone()/finalize()/wait()、notify()、notifyAll()
- Object类只声明了一个空参构造器
面试题:==和equals()区别:
- 回顾==的使用:
==:运算符
- 可以使用在基本数据类型变量和引用数据类型变量中
- 如果比较的是基本数据类型变量,比较两个变量的保存的数据是否相等。(不一定类型要相同)
如果比较的是引用类型变量,比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体。
补充:==符号使用时,必须保证符号左右两边的变量类型一致
- equals()方法的使用:
- 是一个方法,而非运算符
- 只适用于引用数据类型
- Object类中equals()的定义:
public boolean equals(Object obi) {
return (this == obj);
}
说明:Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体。
- 像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址值是否相同,而是比较两个对象的“实体内容”是否相同
- 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的“实体内容”是否相等。那么,我们就需要对Object类中的equals()进行重写
重写的原则:比较两个对象的实体内容是否相同
重写举例:
public boolean equals(Object obj){
if(this == obj){//判断当前的地址值是否和参数的地址值相同,若相同,那么两个
两个值一定相等
return true;
}
if (obj instanceof Object){//判断obj是否是Object的实例
Order order =(Order)obj;//强制类型转换
return this.orderId == order.orderId&&
this.orderName.equals(order.orderName);
}
return false;
}
Object类中toString()的使用:
- 当我们要输出一个对象的引用时,实际上就是调用当前对象的toString()
- Object类中的toString()的定义:
- 像String、Date、File、包装类等都重写了Object类中的toStirng()方法。
使得在调用对象的toString()时,返回“实体内容”信息
- 自定义类也可以重写toString()方法,当调用此方法时,返回对象的“实体内容”
Java中的Junit单元测试:
步骤:
- 选中当前工程 – 右键选择:build path – add libraries – Junit 4 – 下一步
创建Java类,进行单元测试。用于Eclipse
- 此时的Java类的要求:①此类时public的 ②此类提供公共的无参构造器
- 此类中声明单元测试方法。
此时的单元测试方法:方法的权限时public,没有返回值,没有形参
- 此单元测试方法上需要声明注释:@Test,并在单元测试类中导入:import org.junit.Test;
- 生命好单元测试方法以后,就可以在方法体内测试相关代码
- 写完代码以后,左键双击方法名,右键:run as – Junit Test
说明:
- 如果执行没有任何异常:绿条
- 如果执行结果异常:红条
包装类的使用:
- java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征
- 掌握基本数据类型、包装类、String三者之间的转换
JDK 5.0 新特性:自动装箱和自动拆箱
自动装箱: 基本数据类型à包装类
int num = 2;
Interger in1 = num;//自动装箱
boolean b1 = true ;
Boolean b2 =b1;//自动装箱
自动拆箱:包装类à基本数据类型
System.out.println(in1.toString());
int num3 = in1 ;//自动拆箱
面试题:
@Test
public void test3(){
Integer i =new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);//false
//Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],
//保存了从-128~127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围//-128@127范围内,可以直接使用数组中的元素,不用再去new了。目的:提高效率
Integer m = 1;//自动装箱
Integer n = 1;
System.out. println(m ==n);//true
Integer x= 128;
Integer y = 128;
System.out. println(x == y);//false
}
例题解析:
package com.test.exer;
import java.util.Scanner;
import java.util.Vector;
/*
利用Vector代替数组处理。从键盘读入学生成绩(以负数代表输入结束),找出最高分,并输出学生成绩等级。
提示。数组一旦创建,长度就固定不变,所以在创建数组前就需要知道它的长度。
而向量类java.util.vector可以根据需要动态伸缩。
创建Vector对象:Vector v=new Vector();
给向量添加元素: v.addElement(0bject obj); //obj必须是对象
职出向量中的元素:Object obj=v.elementAt(0);
注意第一个元素的下标是0,返回值是Object类型的。
计算向量的长度:v.size();
若与最高分相差10分内:A等:20分内:B等;
30分内:C等,其它:D等
*/
public class ScoreTest {
public static void main(String[] args) {
//1.实例化Scanner ,用于从键盘中获取学生成绩
Scanner scan = new Scanner(System.in);
//2.创建Vector对象:
// 创建Vector对象:Vector v=new Vector();相当于原来的数组
Vector v = new Vector();
//3.通过for(;;)或while(true)方式,
// 给Vector中添加数组:v.addElement(Object obj)
int maxScore = 0;
for (; ; ) {
System.out.println("请输入学生成绩(输入负数代表结束)");
int score = scan.nextInt();
if (score < 0) {
break;
}
if (score > 100) {
System.out.println("输入的数据非法,重新输入");
continue;
}
//3.1添加操纵:v.addElement(inScore);
//JDK 5.0之前:
// Integer inScore = new Integer(score);
// v.addElement(inScore);//多态
//JDK 5.0 之后
v.addElement(score);//自动装箱
//4.获取当前成绩最大值
if (maxScore < score) {
maxScore = score;
// System.out.println("最大值为:"+maxScore);
}
}
//5.遍历Vector,得到每个学生的成绩,并于
char level;
for(int i = 0;i<v.size();i++){
Object obj=v.elementAt(i);
//jdk 5.0之前:
// Integer inScore = (Integer)obj;
// int score = inScore.intValue();
int score =(int)obj;
if(maxScore - score<=10){
level ='A';
}else if(maxScore - score <=20){
level ='B';
}else if(maxScore - score <=30){
level = 'C';
}else {
level = 'D';
}
System.out.println("student- "+i+",score is "+score +",level is"+level);
}
System.out.println("最大值为:"+maxScore);
}
}
关键字:static的使用
- static:静态的
- static可以用来修饰:属性、方法、代码块、内部类
- 使用static来修饰属性:静态变量,
3.1属性,按是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)
实例变量:我们创建了多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
静态属性:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,对导致其他对象调用此静态变量时,时修改过了的。
3.2static修饰属性的其他说明:
①静态变量随着类的加载而加载。可以通过的“类.静态变量“的方式来调用
②静态变量的加载早于对象的创建。
③由于类只会加载一次,则静态变量在内存中也只会存在一份,存在方法区
静态域中
④ 类变量 实例变量
类 yes no
对象 yes yes
3.3静态属性举例: System..out;Math.PI;
- 使用static修饰方法:静态方法
- 随着类的加载而加载,可以通过的“类.静态变量“的方式来调用
- 类变量 实例变量
类 yes no
对象 yes yes
-
- 静态方法中,只能调用静态的方法或属性
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
- static注意点:
5.1在静态的方法内,不能使用this关键字、super关键字
5.2对于静态属性和静态方法的使用,从生命周期的角度理解
- 开发中,如何确定一个属性是否要声明为static的?
>属性是可以被多个对象所共享的,不会随着对象的不同而不同
>类中的常量也常常声明为static
开发中,如何确定一个方法是否要声明为static的?
>操作静态属性的方法,通常设置为static的
>工具类中的方法,习惯上声明为static的,比如,Math、Arrays、Collections
单例(Singleton)设计模式
- 所谓的类的单例设计模式,就是采取一定的方法保证再整个的软件系统中,对某个类只能存在一个对象实例:
- 如何实现?
- 饿汉式单例模式的实现:
静态的方法中只能调用静态的属性
如下调用:
2.懒汉式单例模式的实现:
如下调用:
3.区分饿汉式和懒汉式
饿汉式:
坏处,对象加载时间过长。
好处,饿汉式是线程安全的
懒汉式:
好处,延迟对象的创建。
目前的写法坏处:线程不安全à到多线程内容时,再修改
4.单例模式设计模式的应用场景:
mian()方法的使用说明:
- main()方法作为程序的入口
- main()方法也是一个普通的静态方法
- main()方法也可以作为我们与控制台交互的方式。(之前:使用Scanner)
代码块(初始化块)
- 代码块的作用:
用来初始化类、对象
- 代码块如果有修饰的化,只能使用static
- 分类:静态代码块 vs 非静态代码块
- 静态代码块:
>内部可以有输出语句
>随着类的加载而执行,而且只会执行一次
>作用:初始化类的信息
>如果一个类中定义了多个静态代码块,则按声明的先后顺序执行
>静态代码块的执行,优先于非静态代码块的执行
>静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
- 非静态代码块:
>内部可以有输出语句
>随着对象的创建而执行
>没创建一个对象,就执行一次非静态代码块
>作用:可以在创建的时候,对对象的属性等进行初始化
>非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法
对属性可以赋值的位置:
-
- 默认初始化
- 显式初始化
- 构造器中初始化
- 有了对象以后,可以通过"对象.性"或"对象.方法"的方式,进行赋值
- 在代码块中赋值
执行顺序:① - ② /⑤ - ③ - ④
final
关键字的使用
在Java中声明类、属性和方法时,可使用关键字final
来修饰。
final
标记的类不能被继承;final
标记的方法不能被子类复写;final
标记的变量(成员变量或局部变量)即为常量,只能赋值一次。
final
关键字修饰类、成员变量和成员方法
1.final
类
final
用来修饰一个类,意味着该类成为不能被继承的最终类。出于安全性的原因和效率上的考虑,有时候需要防止一个类被继承。例如,Java
类库中的String
类,它对编译器和解释器的正常运行有着很重要的作用,不能轻易改变它,因此把它修饰为final
类,使它不能被继承,这就保证了String
类的惟一性。同时,如果你认为一个类的定义己经很完美,不需要再生成它的子类,这时也应把它修饰为final
类。
定义一个final
类的格式如下:
- final class ClassName{
- ...
- }
注意:声明为final
的类隐含地声明了该类的所有方法为final
方法。
下面的结论是成立的:声明一个类既为abstract
,又为final
是非法的,因为抽象类必须被子类继承来实现它的抽象方法。下面是一个final
类的例子:
- final class A{
- ...
- }
- class B extends A{//错误!不能继承A
- ...
- }
2.final
修饰成员变量
变量被声明为final
后,成为常值变量(即常量),一旦被通过某种方式初始化或赋值,即不能再被修改。通常 static
与final
一起 使用来指定一个类常量。例如:
- static final int SUNDAY=0;
把final
变量用大写字母和下划线来表示,这是一种编码规定。
3.final
修饰成员方法
用final
修饰的方法为最终方法,不能再被子类重写,可以被重载。
尽管方法重写是Java非常有力的特征,但有时却需要避免这种情况的发生。为了不允许一个方法被重写,在方法的声明中指定final
属性即可。例如:
- class A{
- final void method(){}
- }
- class B extends A{//定义A类的一个子类B
- void method(){}//错误,method()不能被重写
- }
该例中,因为method()
方法在A
中被声明为final
,所以不能在子类B
中被重写。如果这样做,将导致编译错误。
方法被声明为final
有时可以提高性能:编译器可以自由地内联调用它们,因为它“知道”它们不会被子类重写。
完成的题目如下:
package com.test.exer2; /* *编写一个类实现银行账户的概念,包含的属性有""帐号”"、“"密码”、"存款余额”、"“利率”"、"最小余额" * 定义封装这些同性的方法。账号要自动生成。 编写主类,使用银行账户类,输入、输出3个储户的上述信息。 * 考虑:哪些属性可以设计成static属性。 */ public class Account { private int id; private String pwd = "000000"; private double balance; private static double interestRate; private static double minMoney = 1.0; private static int init = 1001;//用于自动生成id使用 public Account(){ id = init++; } public Account(String pwd,double balance){ id = init++; this.pwd = pwd; this.balance = balance; } public int getId() { return id; } public static double getInterestRate() { return interestRate; } public static void setInterestRate(double interestRate) { Account.interestRate = interestRate; } public static double getMinMoney() { return minMoney; } public static void setMinMoney(double minMoney) { Account.minMoney = minMoney; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } public double getBalance() { return balance; } @Override public String toString() { return "Account{" + "id=" + id + ", pwd='" + pwd + '\'' + ", balance=" + balance + '}'; } }
package com.test.exer2; /* *编写一个类实现银行账户的概念,包含的属性有""帐号”"、“"密码”、"存款余额”、"“利率”"、"最小余额" * 定义封装这些同性的方法。账号要自动生成。 编写主类,使用银行账户类,输入、输出3个储户的上述信息。 * 考虑:哪些属性可以设计成static属性。 */ public class AccountTest { public static void main(String[] args) { Account acct1 =new Account(); Account acct2 = new Account("123456",500); Account.setInterestRate(0.012); Account.setMinMoney(100); System.out.println(acct1); System.out.println(acct2); } }
package com.ai; import java.util.Scanner; public class ObjectTest { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int num1 = sc.nextInt(); int num2 = sc.nextInt(); // 在测试类中创建Demo类对象d1,传入输入值num1, d1调用toString方法并打印输出该值 // 创建Demo类对象d2,同样传入输入值num1,打印判断d1和d2是否相等(实际是比较地址) /********* Begin *********/ Demo d1 = new Demo(num1); d1.toString(); Demo d2 = new Demo(num1); System.out.println(d1.equals(d2)); /********* End *********/ // 创建Person类对象p,传入输入值num2,打印判断d1和p是否相等(实际是比较地址) /********* Begin *********/ Person p = new Person(num2); System.out.println(d1.equals(p)); /********* End *********/ } } class Demo { private int num; public Demo(int num) { this.num = num; } public boolean equals(Object obj) // Object obj = new Demo() { if (!(obj instanceof Demo)) // 判断obj是否和Demo是同类 return false; Demo d = (Demo) obj; // 将父类的引用(Object)向下转换为子类(Demo) return this.num == d.num; } public String toString() { return "Demo:" + num; // 返回对象的值(每一个对象都有自己的特定的字符串) } } class Person { private int num; public Person(int num) { this.num = num; } }
package com.exer; /* 从键盘输入一串字符,输出有多少个不同的字符、每个字符出现的次数。 */ import java.util.Scanner; public class test { public static void main(String[] args) { Scanner input=new Scanner(System.in); String str=input.nextLine(); StringBuffer k=new StringBuffer(str); System.out.println(k); System.out.println("共有"+k.length()+"个字母!"); String a; int index,sum; for(int i=0;i<k.length();) { sum=0; a=k.substring(0,1); index=k.indexOf(a); while(index!=-1) { sum++; k.deleteCharAt(index); index=k.indexOf(a,index); } System.out.println(a+"字母有"+sum+"个"); } } }