Java面向对象学习的三条主线:
1.Java类及类的成员:属性,方法,构造器;代码块,内部类
2.面向对象的三大特征:封装性,继承性,多态性,(抽象性)
3.其他关键字:this,super,static,final,abstract,interface,package,import等
1.Java类及类的成员:
1.面向过程和面向对象
1.面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做
举例:人把大象装冰箱
①把冰箱门打开
②抬起大象,塞进冰箱
③把冰箱门关上
2.面向对象:强调的是具备了功能的对象,以类/对象为最小单位,考虑谁来做
人{
}
冰箱{
}
大象{
}
理解万事万物皆对象
1.在Java语言范畴内,我们都将功能,结构等封装的类中,通过类的实例化,来调用具体的功能
2.涉及到Java与前端HTML,后端数据库交互时,前后端的结构在Java层面交互时,都体现为类,对象
2.Java语言基本元素:类和对象
定义:
类:对一类事物的描述,是抽象的,概念上的定义
对象:是实际存在的该类事物的每个个体,因而也称为实例
3.类和对象的使用
①创建类,设计类的成员
②创建类的对象
③通过“对象.属性”或“对象.方法”调用对象的结构
举例:
package day008;
public class Test {
public static void main(String[] args) {
//创建Person类的对象
Person p1 = new Person();
Person p2 = new Person();
//调用对象的结构:属性,方法
//调用属性:对象.属性
p1.name = "Tom";
p1.age = 19;
System.out.println(p1.name);
System.out.println(p2.name);
//调用方法:对象.方法
p1.eat();
p1.sleep();
p1.talk("chinese");
}
}
//创建类
class Person{
//属性
String name;
int age;
boolean isMale;
//方法
public void eat(){
System.out.println("人可以吃饭。");
}
public void sleep(){
System.out.println("人可以睡觉。");
}
public void talk(String language){
System.out.println("中国人说:" + language);
}
}
4.属性(成员变量)VS局部变量
相同点
1.定义变量的格式:数据类型 变量名 = 变量值
2.先声明,后使用
3.变量都有其对应作用域
不同点
1.在类中声明的位置不同
成员变量:直接定义在类的一对{ }内
局部变量:声明在方法内,方法形参,代码块内,构造器形参,构造器内部的变量
2. 关于权限下修饰符的不同
成员变量:可以在声明时,指明其权限,使用权限修饰符。
局部变量:不可以使用权限修饰符。
3. 默认初始化值的不同
成员变量:根据其类型,都有初始化值。
整形(byte,short,int,long):0
浮点型(float,double):0.0
字节型(char):0
布尔型(boolean):flase
引有数据类型(类,数组,接口):null
局部变量:没有默认初始化值。
4.在内存中加载的位置不同:
属性:加载的堆空间中(非static)
局部变量:加载到栈空间中
举例代码
public class day001 {
public static void main(String[] args) {
Person p1 = new Person();
System.out.println(p1.name);
System.out.println(p1.age);
p1.eat();
p1.talk("英语");
}
}
class Person{
public String name;//成员变量
public int age;//成员变量
public void eat(){
String food="包子";//food:局部变量(方法内)
System.out.println("人可以吃:" +food);
}
public void talk(String language){//language:局部变量(方法形参)
System.out.println("人可以说话,使有的是:" +language);
}
}
运行结果
5.方法的声明和使用
①方法的声明
权限修饰符 返回值类型 方法名(形参列表){
方法体
}
举例:
public void eat(String food){
System.out.println("人们喜欢吃 " + food);
)
②说明:
权限修饰符:public,private,protect,缺省
返回值类型: 有返回值 VS 没返回值
如果有返回值,则必须在方法声明时,指定返回值的类型 。同时,在方法中,必须使用return关键字来返回指定类型的数据。“return 数据;”
如果没有返回值,则在方法声明时,使用void来表示。不能使用return.如果使用只能用“return;”来表示结束此方法。
方法名:属于标识符,要见名知意
形参列表:方法可以有1个,2个·····多个形参
格式:数据类型 形参名,数据类型 形参名,····
方法体:方法功能的实现
③方法的声明
1.方法可以调用当前类的属性和方法
2.方法中不可以定义方法
6.再谈方法
1 方法的重载
①定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或参数类型不同即可
②举例:
class Person{
public void eat(){
}
public void eat(String food){
}
}
③判断是否是重载(跟方法的权限修饰符,返回值类型,形参变量名,方法体都没有关系)
④由重载可以知道,调用一个方法,除了看方法名,还要看形参列表。
例题:
判 断:
与void show(int a,char b,double c){}构成重载的有:
a) void show(int x,char y,double z){} // no
b) int show(int a,double c,char b){} // yes
c) void show(int a,double c,char b){} // yes
d) boolean show(int c,char b){} // yes
e) void show(double c){} // yes
f) double show(int x,char y,double z){} // no
g) void shows(){double c} // no
2 可变个数形参的方法(jdk 5.0新增内容)
①格式 数据类型 … 变量名;
②当调用可变个数形参的方法时,传入的参数个数可以是0个,1个,2个········
③可变个数形参的方法与本类中同名方法,形参个数不同的方法之间构成重载
④可变个数形参的方法与本类中同名方法,形参类型相同的数组之间不构成重载(二者不能同时存在)
⑤可变个数形参在方法的形参中,必须声明在末尾
⑥可变个数形参在方法的形参中,最多只能声明一个可变个数形参
举例:
package day009;
public class Test2 {
public static void main(String[] args) {
Person p = new Person();
p.eat("11","22");//胡辣汤
p.eat("3");//面条
p.eat();//胡辣汤
}
}
class Person{
public void eat(String ... food){//可变个数形参
System.out.println("胡辣汤");
}
public void eat(String food){
System.out.println("面条");
}
}
3 方法参数的值传递机制
先了解
变量的赋值:
如果变量是基本数据类型,此时赋值的是变量所保存的数据值
如果变量时引用数据类型,此时赋值的是变量所保存的数据地址值
m = n;
Person.m = Person.n;
1.形参:方法定义时:声明在()内的参数
实参:方法调用时,实际传递给形参的数据
2.值传递机制:
如果参数是基本数据类型,此时实参赋给形参的是实参真实储存的数据值
如果参数是引用数据类型,此时实参赋给形参的是实参储存数据的地址值
举例:
package day009;
public class Test3 {
public static void main(String[] args) {
Data data = new Data();
data.m = 20;
data.n = 10;
System.out.println("m = " + data.m + ", n = " + data.n);
data.swap(data);
System.out.println("m = " + data.m + ", n = " + data.n);
}
}
class Data{
int m;
int n;
public void swap(Data data1){
int temp = data1.m;
data1.m = data1.n;
data1.n = temp;
}
}
package day009;
public class Test4 {
public static void main(String[] args) {
int[] arr = new int[]{5,8,9,7,4,6,5,1,75};
Test4 t = new Test4();
//遍历数组
for (int i = 0;i < arr.length;i++){
System.out.print(arr[i] + " ");
}
System.out.println();
t.swap(arr,1,2);
//遍历数组
for (int i = 0;i < arr.length;i++){
System.out.print(arr[i] + " ");
}
}
//交换数组中指定两个位置元素的值
public void swap(int[] a,int i,int j){
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
4 递归方法
定义:
1.递归方法:一个方法体内调用它自身
2.方法递归包含了一种隐式循环,递归一定要像以知方向循环,否者就会变成死循环
举例:
package day009;
public class Test9 {
public static void main(String[] args) {
Test9 t = new Test9();
System.out.println( t.sum(10));
}
//返回1~n各个数的和
public int sum(int n){
if (n == 1){
return 1;
}else{
return n + sum(n-1);
}
}
}
7.匿名对象的使用
1.理解:我们创建的对象,没有显示的赋给一个变量名。即为匿名对象
2.特征:匿名对象只能调用一次
3.使用:
举例:
package day009;
public class Test {
public static void main(String[] args) {
//匿名对象
new Phone().price = 1999;
new Phone().showPrice();//0.0
}
}
class Phone{
double price;
public void showPrice(){
System.out.println("手机价格是:" + price);
}
}
8.构造器的理解
1.构造器的作用
1.创建对象:Person p= new Person();(new 构造器)
2.创建对象的同时,可以给对象的属性赋值
举例
package day010;
public class Test1 {
public static void main(String[] args) {
Dog d = new Dog();//使用了构造器
Dog d1 = new Dog("大黄");
System.out.println(d1.name);
}
}
class Dog{
//属性
String name;
//构造器
public Dog(){
System.out.println("使用了构造器");
}
public Dog(String n){
name = n;
}
}
2.说明
1.如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
2.一旦我们显示的定义了构造器(无论是否有形参),系统就不会再提供默认的构造器
3.构造器的格式:权限修饰符 类名(形参列表){}
4.一个类中定义的多个构造器也叫重载
5.一个类中至少有一个构造器
6.父类的构造器不可被子类继承
7.默认构造器的修饰符与所属类的修饰符一致
例题:
package day010;
/*
编写两个类,TriAngle和TriAngleTest,其中TriAngle类中声明私有的底
边长base和高height,同时声明公共方法访问私有变量。此外,提供类
必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。
*/
public class TriAngleTest {
public static void main(String[] args) {
TriAngle t = new TriAngle(2,4);
System.out.println("三角形的面积是:" + t.getBase() * t.getHeight());
}
}
class TriAngle{
//属性
private int base;
private int height;
//构造器
public TriAngle(int b,int h){
base = b;
height = h;
}
public int getBase(){
return base;
}
public int getHeight(){
return height;
}
}
9.JavaBean
所谓JavaBean,是指符合如下标准的java类
1.类是公共的
2.有一个无参的公共过的构造器
3.有属性,且有对应的set,get方法
10.方法的重写
1.重写:
子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作
2.应用:
重写以后,当创建子类对象以后,通过子类对象调用子父类中同名同参数的方法时,实际执行的是子类重写的父类的方法
3.重写的规定(子类中的叫重写的方法,父类中的叫被重写的方法)
①重写的方法名和形参列表相同
②子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符(子类不能重写父类中声明为private权限的方法)
③返回值类型
父 (void) 则子 (void)
父 (A类型) 则子(A类或A类的子类)
父 (基本数据类型) 则子(相同的基本数据类型)
4.说明:
子类和父类的同名同参数的方法要么都声明为static(不是重写)要么都声明s非tatic(考虑重写)
11.Object类的使用
java.lang.Object类
1.Object类是所有类的父类
2.Object类中的功能(属性和方法)就具有通用性
属性:无
方法:equals()/ tostring()/ getClass()/ hashCode() /clone() /finalize()/ wait()
3.Object类只声明一个空参构造器
12.== 与equals()的区别
1.==
1.可以在基本数据类型和引用数据类型中使用
2.基本数据类型:比较两个变量保存的数据是否相等
引用数据类型:比较两个对象的地址值是否相等
3.举例
int i =10;
char c = 10;
double b = 10.0;
则 i == c == b;(自动类型提升)
2.equals()
1.是一个方法而非运算符
2.只能适用于引用数据类型
3.Object中equals()的定义:
public Boolean equals (Object obj){
return (this == obj);
}
说明;Object类中定义的equals()和==的作用是相同的,比较两个对象的地址值是否相同
4.像String,Date,File,包装类等都重写了equals()方法。重写后,比较的是两个对象的实体内容是否相同
5.通常情况下,我们自定义的类使用equals(),也是比较的是两个对象的实体内容是否相同,所以我们要重写equals()方法。
package day013;
public class EqualsTest {
public static void main(String[] args) {
Student s1 = new Student("王祖贤",18);
Student s2 = new Student("王祖贤",18);
System.out.println(s1.Object(s2));
}
}
class Student{
String name;
int age;
public Student(String name,int age){
this.name = name;
this.age = age;
}
public boolean Object(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof Student) {
Student s = (Student) obj;
if ( this.age == s.age && this.name.equals(s.name)) {
return true;
}
}
return false;
}
}
13.Object类中toString()的使用
1.当我们输出一个对象的引用时,实际上就是调用当前对象的toString()
Person p = new Person(“刘德华”,18);
System.out.println(p); //地址值
System.out.println(p.toString());//地址值
2.Objec类中toString()
返回调用对象的地址值
3.像String,Date,File,包装类等都重写了Object类中的toString()方法。使得在调用对象的toString()时,返回“实体内容”信息
4.自定义类也可以重写toString()方法,当调用此方法是,返回“实体内容”信息
public String toString(){
return " " ;
}
举例
public String toString() {
return "Order{" + "orderId=" + orderId + ", orderName='" + orderName + '\'' + '}';
}
14.包装类的使用
1.
package day013;
public class Wrapper {
public static void main(String[] args) {
//基本数据类型--->包装类的对象(调用包装类的构造器)
int num = 10;
Integer int1 = new Integer(num);
Integer int2 = new Integer("123");
System.out.println(int1.toString());//10
System.out.println(int2.toString());//123
Boolean b = new Boolean("true123");
System.out.println(b);//false
//包装类的对象--->基本数据类型 (调用包装类的Xxx的xxxValue())
Integer int3 = new Integer(10);
int i1 = int3.intValue();
System.out.println(i1 + 1);//11
}
}
package day013;
public class Test2 {
public static void main(String[] args) {
/*
jdk 5.0新特性,自动装箱和自动拆箱
*/
//自动装箱 基本数据类型--->包装类的对象
int i = 10;
Integer int1 = i;
System.out.println(int1.toString());
boolean b = true;
Boolean boo = b;
System.out.println(boo.toString());
//自动拆箱 包装类的对象--->基本数据类型
Integer int22 = i;
int i1 = 10;
System.out.println(i1);
}
}
package day013;
public class Test3 {
public static void main(String[] args) {
//基本数据类型,包装类--->String类型
//方式一,使用连接运算
int i = 10;
String s1 = i + "";
Integer int1 = i;
String s2 = int1 + "";
System.out.println(s1);
System.out.println(s2);
//方式二,调用String的valueOf(变量)。
float f1 = 12.3f;
String s3 = String.valueOf(f1);
Double d = new Double(45.250);
String s4 = String.valueOf(d);
System.out.println(s3);
System.out.println(s4);
//String类型--->基本数据类型,包装类
//调用包装类的parseXxx(String s)
String str3 = "123";
int i1 = Integer.parseInt(str3);
System.out.println(i1);
String str4 = "true123";
boolean b1 = Boolean.parseBoolean(str3);
System.out.println(b1);
}
}
15.理解main方法的语法
1.main()方法作为程序的入口
2.main()方法也是一个普通的静态方法
3.main()方法可以作为我们与控制台交互的方式
16.代码块
1.代码块的作用:用来初始化类和对象
2.代码块如果有修饰的话,只能使用static
3.代码块格式
①
{
}
②
static{
}
4.分类:静态代码块 VS 非静态代码块
静态代码块
1.内部可以有输出语句
2.随着类的加载而执行,而且只执行一次
3.作用:初始化类的信息
4.如果一个类中定义多个静态代码块,则按声明的先后顺序执行
5.静态代码块内只能调用静态的属性和方法
非静态代码块
1.内部可以有输出语句
2.随着对象的创建而执行,而且每创建一次就执行一次
3.作用:可以在创建对象时,对对象的属性等进行初始化
3.如果一个类中定义多个非静态代码块,则按声明的先后顺序执行
4.非静态代码块内能调用静态的属性和方法,也能调用非静态的属性和方法
5.举例
package day014;
public class BlockTest {
public static void main(String[] args) {
Student.study();
Student s1 = new Student();
Student s2 = new Student();
String s = Student.school;
}
}
class Student{
static String school = "监狱";
static{
System.out.println("Static 代码块");
}
{
System.out.println("代码块");
}
public static void study(){
System.out.println("我们喜欢学习.");
}
}
输出
Static 代码块
我们喜欢学习.
代码块
代码块
17.内部类
1.Java中允许将一个类A声明在另一个类B中,则类·A是内部类,类B是外部类
2.内部类的分类:成员内部类(非静态,静态) VS 局部内部类(代码块内,方法内,构造器内)
3.成员内部类:
一方面,作为外部成员
①调用外部类的结构
②可以被static修饰
③可以被四种不同的权限修饰
另一方面,作为一个类
4.如何实例化成员内部类的对象
静态成员内部类
Person.Dog dog = new Person.Dog();
非静态成员内部类
Person p = new Person();
Person.Dog dog = p.new Dog();
5.如何在成员内部类中区分调用外部类的结构
public void play(String name){
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性
}
6.开发中局部内部类的使用
public Animal getAnimal(){
class AA implements Animal{
}
return new Animal();
}
2.面向对象的三大特征
1.封装性
1.问题的引入
当给属性赋值有额外的限制条件时,我们只能创建方法来给属性赋值和获取属性。为了避免用户直接使用属性f赋值,我们必须将属性私有化(private)
举例:
创建程序,在其中定义两个类:Person和PersonTest类。定义如下:
用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。 在 PersonTest 类 中实例化 Person 类的对象 b , 调 用 setAge() 和
getAge()方法,
package day010;
public class PersonTest {
public static void main(String[] args) {
Person b = new Person();
b.setAge(5);
System.out.println("age: " + b.getAge());
}
}
class Person{
private int age;
public void setAge(int n){
if (n >= 0 && n <= 130){
age = n;
}else{
System.out.println("输入数字错误!");
}
}
public int getAge(){
return age;
}
}
2.封装性的体现
1.我们将属性私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)属性
2.不对外暴露的私有的方法
3.单例模式
······
3.四种权限修饰符的理解
Java规定的四种权限(从小到大排列):private,缺省,protected,public
四种权限可以用来修饰类和类的内部结构:属性,方法,构造器,内部类
具体的:
四种权限都可以用来修饰类的内部结构:属性,方法,构造器,内部类
修饰类的话只能用:缺省,public
2.继承性
1.继承的好处
①减少了代码的冗余
②便于功能的扩展
③为之后多态性的使用,提供了前提
2.继承的格式
格式:class A extends B { }
A:子类,派生类
B:父类,超类,基类
3.继承的体现`
1.一旦子类A继承父类B以后,子类A就获取了父类B中声明的所有的属性和方法。
特别的,父类中声明为private的属性和方法,子类继承父类以后,仍然认为获取了父类的私有的结构。只是因为封装性的影响,使得子类不能直接调用父类中的结构而已。
2.子类继承父类以后,还可以声明自己的属性和方法,实现功能的扩展。
4.继承性的规定
1.一个类可以被多个子类继承
2.类的单继承性:一个类只有一个父类
3.子父类是相对的概念
4.子类直接继承的父类,称为:直接父类。
间接继承的父类,称为:间接父类。
5.子类继承父类以后,就获取直接父类以及所有间接父类中所有的属性和方法
5
1.如果我们没有显示的声明一个类的父类的话,则此类继承于java.lang.Object类
2.所有的类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类
3.意味着,所有的Java类具有java.lang.Object类声明的功能
3.多态性
1.理解多态性:可以理解为一个事物的多种形态
2.何为多态性:
对象的多态性:父类的引用指向子类的对象(Person p = new Man()😉
3.多态的使用:虚拟方法调用
有了对象的多态性以后,我们在编译期,只能调用父类中的方法,但在运行期,我们实际执行的是子类重写的父类的方法(编译看左边,运行看右边)
虚拟方法调用理解
正常的方法调用
Person e = new Person();
e.getInfo();
Student e = new Student();
e.getInfo();
虚拟方法调用(多态情况下)
子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。
Person e = new Student();
e.getInfo(); //调用Student类的getInfo()方法
编译时类型和运行时类型
编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类 的getInfo()方法。——动态绑定
4.多态性使用的前提:
①类的继承关系中
②方法的重写
5.对象的多态性:只适用于方法,不适用于属性(编译和运行都看左边)
3.其他关键字
1.return
1.使用范围:方法体中
2.作用:①结束方法 ②针对于有返回值类型的方法,使用“return 数据;”返回数据。
3.注意点:return关键字后面不能声明执行语句
2.this
1.this可以用来修饰:属性,方法,构造器
2.this修饰属性和方法 this理解为:当前对象
this修饰构造器 this理解为:当前正在创造的对象
3.在类的方法中,我们可以使用”this.属性“或”this.方法“的方式,调用当前对象的属性或方法。但是,通常情况下我们都选择省略”this.”。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用“this.变量”的方式,表明此变量是属性而非形参
4.在类的构造器中,我们可以使用”this.属性“或”this.方法“的方式,调用当前正在创造的对象的属性或方法。但是,通常情况下我们都选择省略”this.”。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式的使用“this.变量”的方式,表明此变量是属性而非形参
5.this调用构造器
1.我们在类的构造器中,可以显示的使用“this(形参列表)”方式,调用本类中指定的其他构造器
2.构造器不能使用“this(形参列表)”方式调用自己
3.如果一个类中有n个构造器,则最多有n-1个构造器使用了“this(形参列表)”
4.规定:"tnis(形参列表)"必须声明在当前构造器的首行
5.构造器内部最多只能声明一个“this(形参列表)”
举例
package day010;
public class Test3 {
public static void main(String[] args) {
Boy b =new Boy("Tom");//*********
}
}
class Boy{
private String name;
private int age;
public Boy(){
System.out.println("*********");
}
public Boy(String name){
this();
this.name = name;
}
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;
}
}
3.package
1.为了更好的实现项目中类的管理,提供包的概念
2.使用package声明类或接口所属的包,声明在源文件的首行
3.包名,属于标识符
4.每“ . ”一次,就代表一层文件目录
5.同一个包下,不能命名同名的接口或类
不同的包下,能命名同名的接口或类
4.import
import:导入
1.在源文件中显式的使用import结构导入指定包下的类,接口
2.声明在包的声明和类的声明之间
3.如果需要导入多个结构,则并列写成即可
4.可以使用“xxx.*”的方式,表示导入xxx包下的所有结构
5.如果使用的类或接口是java.lang包下定义的,则可以省略impor结构
6.如果使用的类或接口是本包下定义的,则可以省略import结构
7.如果在源文件中,使用了不同包下的同名的类,则必须至少有一个需要以全类名的方式显示
8.使用“”xxx.*“方式表明可以调用xxx包下的所有结构,但是如果使用的是xxx子包下的结构,则仍需要显示导入(xxx.子包.*)
9.import static:导入指定类或接口中的静态结构(属性和方法)。
6.super
1.super的理解:
父类的
2.super可以用来调用:
属性,方法,构造器
3.super的使用(属性和方法):
我们可以在子类的方法或构造器中,通过使用”super.属性“或”super.方法“的方法显式调用父类中声明的属性和方法(有时可以省略)
4.super调用构造器
①格式:super(形参列表);
②”super(形参列表)“必须声明在子类构造器的首行
③”this(形参列表)“或”super(形参列表)“只能二选一,不能同时出现
④在子类构造器首行,没有显示的声明”this(形参列表)“或”super(形参列表)“,则默认调用的是父类中空参构造器:super(形参列表);
⑤在子类的多个构造器中,至少有一个类的构造器中使用了”super(形参列表)“,调用了父类中的构造器(子类对象实例化全过程)
7.instanceof
1.格式:a instanceof A
判断对象a是否是类Adequate实例,如果是返回,true,如果不是返回,false.
2.使用情景:为了避免在向下转型时出现ClassCastException(类型转换错误)的异常,我们再向下转型之前,先使用instanceof判断,一旦返回true,就进行向下转型,返回false,不进行向下转型。
3.如果 a instanceof A 返回true,则a instanceof B也返回true。
其中,类B是类A的父类
4.举例
package day013;
public class PersonTest {
public static void main(String[] args) {
Person person = new Man();
person.p();
//使用强转,可能会出现错误
//Woman woman = (Woman)person;
// woman.w();//java.lang.ClassCastException:
Man man =(Man)person;
man.m();
if (person instanceof Man){
System.out.println("mmmmmmmm");
}
if (person instanceof Woman){
System.out.println("wwwwwwwwwwww");
}
}
}
class Person{
public void p(){
System.out.println("person");
}
}
class Man extends Person{
public void p(){
System.out.println("man");
}
public void m(){
System.out.println("man");
}
}
class Woman extends Person{
public void w(){
System.out.println("woman");
}
}
8.static
1.static : 静态的
2.static可以修饰属性,方法,代码块,内部类
3.使用static修饰属性:静态属性(静态变量)
1.属性按是否使用static修饰分为:静态属性(类属性)VS 非静态属性(实例属性)
实例属性:我们创建了类的多个对象,每个对象都独立的拥有一套类中的实例属性
静态属性:我们创建了类的多个对象,多个对象共享同一个静态变量
2.说明
①静态变量随着类的加载而加载,可以通过”类.静态变量“的方式进行调用
Chinese.nation = "中国";
②静态变量的加载要早于对象的创建
③由于类只会加载一次,则静态变量在内存中也只会存在一份,存在方法区的静态域中
④ 类变量 实例变量
类 yes no
对象 yes yes
3.静态属性举例(”类.静态变量“的方式进行调用): System.out Math.PI
4.使用static修饰方法:静态方法
①随着类的加载而加载。可以通过”类.静态方法“的方法进行调用
② 静态方法 非静态方法
类 yes no
对象 yes yes
③静态方法中,只能调用静态的方法和属性
非静态方法中,可以调用非静态的方法和属性,也可以调用静态的方法和属性
5.static注意点
①在静态方法内,不能使用this,super关键字
②关于静态属性和静态方法的理解,可以从生命周期来理解
6…
①开发中,如何确定一个属性是否要声明static的
属性是可以被多个对象所共享的,不会随着对象的不同而不同(利息)
类中的常量也常常声明为static
②开发中,如何确定一个方法是否要声明static的
操作静态属性的方法,通常是static的
工具类中的方法,习惯上声明static的。比如:Math ,Arrays
7.应用
package day014;
public class CircleTest {
public static void main(String[] args) {
Circle c1 = new Circle();
Circle c2 = new Circle();
Circle c3 = new Circle();
System.out.println(c1.id);
System.out.println(c2.id);
System.out.println(c3.id);
System.out.println(Circle.num);
}
}
class Circle{
int r;//半径
int id;
static int num;//圆的个数
static int init = 101;//圆的序号
public Circle(){
id = init++;
num++;
}
}
9.final
1.final: 最终的
2.final可以用来修饰的结构:类,方法,变量
3.final 修饰类(final class Person{}) 此类不能被其它类继承(String类,System·1类)
4.final 修饰方法 表明此方法不能被重写
5.final 修饰变量 此时的变量就称为常量,不能修改
①修饰属性:可以赋值的位置有(显式初始化,代码块中初始化,构造器中初始化)
②修饰局部变量:修饰的变量就称为常量,不能修改
10.abstract(抽象类和抽象方法)
1.abstract:抽象的
2.abstract可以用来修饰的结构:类,方法
3.abstract修饰类:抽象类(abstract class 类名{})
①此类不能实例化
②抽象类中一定要有构造器,便于子类实例化时调用
③开发中,都会提供抽象类的子类,让子类对象实例化,完成操作
4.abstrct修饰方法:抽象方法
①抽象方法只有方法的声明,没有方法体
格式:public abstract void eat();
②包含抽象方法的类,一定是抽象类。反之,抽象类不一定有抽象方法
③若子类重写了父类中的所有抽象方法后,则此子类才可实例化
若子类没有重写了父类中的所有抽象方法后,则此子类是个抽象类,需要用abstract修饰
5.创建抽象类的匿名子类的匿名对象(接口类似)
①.创建匿名子类的非匿名对象:p
格式:
Person p = new Person(){
重写抽象方法。
};
②.创建匿名子类的匿名对象
格式:
对象.方法(new Person(){
重写抽象方法。
});
举例:
package day015;
public class Test1 {
public static void main(String[] args) {
//创建匿名子类的非匿名对象:a
Animal a = new Animal() {
@Override
public void eat() {
}
};
Test1 t = new Test1();
//②.创建匿名子类的匿名对象
t.eat(new Animal() {
@Override
public void eat() {
}
});
}
public void eat(Animal a){
System.out.println("458962655");
}
}
abstract class Animal{
public abstract void eat();
}
11.interface(接口)
1.接口使用interface来定义
interface class A{
}
2.Java中,接口和类是并列的两个结构
3.如何定义接口:定义接口中的成员
①JDK7及以前,只能定义全局常量和抽象方法
全局变量:public static final的,但是可以省略不写。
抽象方法:public abstract的,但是可以省略不写。
②JDK8: 除了定义全局变量,抽象方法之外,还可以定义静态方法,默认方法。
4.接口中不能定义构造器,意味着接口不能实例化
5.Java开发中,接口通过让类去实现(implements)的方式来使用
格式:
class A implements B,C,D{
}
如果实现类重写了接口中的所有抽象方法,则实现类可以实例化
如果实现类没有重写了接口中的所有抽象方法,则实现类仍然是一个抽象类
6.Java类中可以实现多个接口
格式:
class A extends AAAA implements B,C,D{
}
7.接口与接口之间可以继承,而且可以多继承
接口的使用
1.接口的具体使用:体现多态性
2.接口,实际上可以看作一种规范
JDk8中关于接口的改进
1.Java 8中,你可以为接口添加静态方法和默认方法。从技术角度来说,这是完全合法的,只是它看起来违反了接口作为一个抽象定义的理念。
静态方法:使用 static 关键字修饰。可以通过接口直接调用静态方法,并执行其方法体。我们经常在相互一起使用的类中使用静态方法。你可以在标准库中找到像Collection/Collections或者Path/Paths这样成对的接口和类。
默认方法:默认方法使用 default 关键字修饰。可以通过实现类对象来调用。我们在已有的接口中提供新方法的同时,还保持了与旧版本代码的兼容性。比如:java 8 API中对Collection、List、Comparator等接口提供了富的默认方法。
2.接口中定义的静态方法,只能通过接口来调用
3.通过实现类的对象,可以调用接口中的默认方法。
如果实现类重写了接口中的默认方法,调用时,调用的是重写的方法
4.如果子类继承的父类和实现的接口中有同名同参数的默认方法 如果子类没有重写此默认方法,调用时,调用的是父类中的方法
5.如果实现类实现了多个接口,而这多个接口中有同名同参数的默认方法,如果实现类没有重写此默认方法,调用时会报错,接口冲突(则需要实现类重写此默认方法)
6.如何在子类的方法中调用父类,接口被重写的方法
eat() //调用此类中的
super.eat() //调用父类中的
A.super.eat() //调用接口中的