JAVA基础面向对象
/**
- 方法的演示
- 方法::也称函数,或者叫过程
- 1.用于封装一段特定的逻辑功能
- 2.尽可能的独立,只干一件事
- 3.优点
- 3)可以被调用多次(避免代码重复、结构清晰)
- 4)结构清晰、便于维护( 便于维护、便于合作开发)
- 方法的定义:
- 修饰词 返回值类型 方法名(参数列表){ 方法体 }
- 注意:
-
1)方法可以有参也可以无参,有参更灵活
-
2)方法可以有返回值也可以没有返回值: 无返回值,返回值类型写void
-
有返回值,返回值类型写具体的数据类型
-
(java语法规定,方法在声明时必须指定返回值类型)
-
3)方法体中return:return语句的作用在于结束方法且将数据返回给调用方。
-
有返回值:1.结束方法的执行 2.返回结果给调用方
-
return后的表达式类型必须与方法定义的返回类型匹配
-
无返回值:return;1.结束方法的执行
*何时有返回值?何时没有返回值?
*规律:
*若方法执行完后,方法外面需要该方法中的某个数,就有返回值
若方法执行完后,方法外面不需要该方法中的某个数,就没有返回值
*
/
public class MethodDemo {
public static void main(String[] args) {
/
* 方法的调用
* 无返回值方法: 方法名(有参传参);
* 有返回值方法: 数据类型 变量 = 方法名(有参传参);
* 方法名(有参传参);------几乎不用
/
/
* 无参方法调用:方法名();
/
say();
/
* 有参五返回值方法调用:必须传参数,参数类型必须匹配:方法名(有参传参);
/
//sayHi(); //编译错误,必须传参数
//sayHi(8); //编译错误,参数类型不匹配
sayHi(“zhangsan”); //String name=“zhangsan”
sayHi(“lisi”); //String name=“lisi”
sayHi(“wangwu”); //String name=“wangwu”
/
* 无参有返回值方法调用: 数据类型 变量 = 方法名();
/
int num = getNum();
System.out.println(num); //88
/
* 有参有返回值方法调用: 数据类型 变量 = 方法名(有参传参);
/
double d = plus(5,6); //double num1=5,double num2=6
System.out.println(d); //11
double a = 5.5;
double b = 4.4;
double dou = plus(a,b); //double num1=5.5,double num2=4.4
System.out.println(dou);
a(); //方法的嵌套调用
System.out.println(“over”);
}
/
* 方法的嵌套:方法中调方法
*/
public static void a(){
System.out.println(111);
b();//方法的嵌套调用
System.out.println(222);
}
public static void b(){
System.out.println(333);
}
//有参有返回值
public static double plus(double num1,double num2){
//double num = num1+num2;
//return num; //返回的不是num,而是num里面那个数
return num1+num2; //返回的是num1+num2的值
}
//无参有返回值
public static int getNum(){
//return; //编译错误,必须返回一个值
//return 5.55; //编译错误,返回值类型不匹配
return 88; //1.结束方法的执行 2.返回结果(250)给调用方
}
//有参无返回值
public static void sayHi(String name){
System.out.println("大家好,我叫"+name);
return; //1.结束方法的执行
}
//无参无返回值
public static void say(){
System.out.println("大家好,我叫WKJ");
}
}
/*
*一. 面向过程:数据+方法
- 面向过程的缺陷:
-
1.缺乏对数据的封装(在main方法中所定义的变量并无直接关系)。
-
2.数据和方法(操作数据的)的分离(参数错了容易出错)
- 二.解决方案:面向对象
- 类:数据(成员变量)+方法(1.构造方法给成员变量赋值2.类方法:类的行为和功能)
- 1.面向对象的第一步就是抽象数据类型,所谓抽象数据类型可以理解为:将不同类型的数
- 据的集合组成个整体用来描述一种新的事物。(自造的数据类型)
- 2.类定义了一种抽象数据类型,而类不但定义了抽象数据类型的组成(成员变量),
- 同时还定义了对该类型可以实施的操作(方法)。
- 三.
- 1.什么是类?什么是对象?
- 1)现实世界是由很多很多对象组成的 基于对象抽出了类( 类:类型、类别,代表一类个体 泛指)
- 2)对象:真实存在的单个的个体(特指:此创建对象的过程也通常称为实例化具体那一个)
- 3)类中可以包含:
-
3.1)所有对象所共有的属性/特征---变量(成员变量)
-
3.2)所有对象所共有的行为--------方法
- 4)类是对象的模板,对象是类的具体的实例
- 2.定义类的方法:
-
类的修饰词(默认public或者不写) class{成员变量类型+变量名称 类方法 }
- 注意:一个文件中,可以包含多个类但是public修饰的类只能有一个,并且public修饰的类必须与文件同名
*/
public class Student {//学生类
String name; //成员变量
int age;
String address;
void study(){ //方法
System.out.println(name+"在学习...");
}
void sayHi(){
System.out.println("大家好,我叫"+name+",今年"+age+"岁了,家住"+address);
}
}
package oo.day01;
//学生类的测试类
public class StudentTest {
public static void main(String[] args) {
/*
* 使用new关键字创建学生对象
* new运算的语法为: new 类名();此创建对象的过程也通常称为实例化。
* 类名+引用=new 类名(参数)如果有空的构造也可以:类名+引用=new 类名()
* new之后,所有成员变量都有一个默认的初始值:
* 成员变量如果是:数值类型(byte,short,char,int,long,float,double)默认:0
* boolean类型:false 引用类型NULL
* 为了能够对实例化的对象进行访问控制,需一个特殊的变量,即引用。(zs)
* 引用类型变量可以存储该类对象的地址信息,通常称为“指向该类的对象”,
* 当一个引用类型变量指向该类的对象,就可以通过这个变量对对象实施访问。
* (除8种基本类型之外,用类、接口、数组等声明的变量都称为引用类型变量,简称“引用”)
/
Student zs = new Student();
/
* 访问成员变量:引用.成员变量
/
zs.name = “zhangsan”;
zs.age = 25;
zs.address = “河北廊坊”;
/
* 调用类中的方法:1.无返回值:引用.方法名(有参传参)2.:有返回值: 返回值类型 a=引用.方法名(有参传参)
* 能.出什么看类型
*/
zs.study();
zs.sayHi();
//new之后,所有成员变量都有一个默认的初始值
Student ww = new Student();
ww.study();
ww.sayHi();
/*引用类型变量存储的是对象的地址信息:引用类型之间画等号:指向同一个对象.
* 1)对其中一个引用的修改会影响另外一个 原因:对象只有一份 eg:房子钥匙(一个对象)
* 2)基本类型之间画等号:赋值 1)对其中一个变量的修改不会影响另外一个 原因:数据有两份
* eg:身份证复印件(两份身份证)
/
Student ls=zs;
/
* null和NullPointerException
* null: 1)空,不指向任何对象
* 2)对null值做任何操作都是不合理的, 报空指针异常(NullPointerException)
* 对没有指向对象的引用使用(赋值,调方法啊),
*/
Student st=null;
System.out.println(st.age);//报空指针异常(NullPointerException)
}
}
/*
- Java语法规定,一个类中不可以有两个方法签名(方法名+参数列表)完全相同的方法。
- 一个类中不可以有两个方法的方法名和参数列表都完全相同。
- 如果一个类的两个方法只是方法名相同而参数列表不同,是可以的。(即方法的重载)
- 方法的重载(overload):
- 1)在同一个类中,方法名称相同,参数列表不同(参数的类型,个数,顺序有关、但是和返回值类型,参数名称无关)
- 2)编译器根据签名来绑定调用不同的方法
- 3)遵循“编译期绑定”看引用类型调用方法(使用哪个类的方法看引用类型,具体调用哪个的看签名)
*/
//重载的演示
public class OverloadDemo {
public static void main(String[] args) {
Aoo o = new Aoo();
o.say();
o.say(“zhangsan”);
o.say(25);
o.say(“zhangsan”, 25);
o.say(25, “zhangsan”);
}
}
class Aoo{
void say(){}
//int say(){return 1;} //编译错误,与返回值类型无关
void say(String name){}
//void say(String address){} //编译错误,与参数名称无关
void say(int age){}
void say(String name,int age){}
void say(int age,String name){}
}
/*1.构造方法:构造函数、构造器、构建器
-
1)给成员变量初始化
-
2)与类同名,没有返回值类型
-
3)在创建对象(new)时被自动调用
-
4)若自己不写构造,则编译器默认提供一个无参构造, 若自己写了构造,则编译器不再默认提供
-
5)构造方法可以重载
-
2.构造方法语法结构
-
1)构造方法的名称必须与类名相同。
-
2)构造方法没有返回值,但也不能写void。
-
3)【访问修饰符】类名( ) {构造方法体}访问修饰符只能是public或者不写
-
3.类方法和构造方法的区别:
-
1)类方法:是描述对象的行为,封装对象的功能。构造方法给成员变量初始化的。
-
2)语法上:【访问修饰符】返回值类型 方法名称(参数列表) {方法体 }
*/
public class Student {
String name;
int age;
/*this:指代当前对象,哪个对象调指的就是哪个对象 在方法中访问成员变量之前默认有个this.
*this的用法:- 1)this.成员变量名-----访问成员变量
- 2)this.方法名()-------调用方法
- 3)this()--------------调用构造方法
*/
public Student() {}//默认的构造方法
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
void study(){
System.out.println(name+“在学习…”);
}
void sayHi(){
System.out.println(“大家好,我叫”+name+",今年"+age+“岁了”);
}
/*
- 构造方法的重载
- 1.声明:Cell ( int row , int col ) {}调用:Cell c1 = new Cell ( 5 , 6 );
- 2.声明:Cell ( ) { } 调用:Cell c1 = new Cell ( ) ;
- this()--------------调用构造方法
- 3.声明:Cell (int row) {this(row , row );}调用:Cell c1 = new Cell ( 5 ) ;
*/
}
//super演示
public class SuperDemo { }
/**
2.继承:
1)作用:有利于代码的重用
2)通过extends实现继承
3)父类:共有的属性和方法
子类:特有的属性和方法
4)子类继承父类后,子类具有:
4.1)父类所共有的
4.2)子类所特有的
5)一个父类可以有多个子类
一个子类只能有一个父类—单一继承
6)继承具有传递性
/
class Aoo{}
class Boo extends Aoo{}
/*
- 继承中构造方法: *
java规定:构造子类之前必须先构造父类
子类的构造方法中是必须要通过super关键字来调用父类的构造方法的,
这样才可以保证妥善的初始化继承自父类的成员变量。
若自己不写则编译默认默认提供super()调父类的无参构造
若父类没有提供无参的构造方法,则会出现编译错误。
若自己写了则不再默认提供 super()必须位于子类构造的第一句 .
2. 用子类构造来初始化子类对象时,父类构造总会在子类构造之前执行。
3.super:指代当前对象的父类对象
1)super.成员变量名—访问父类的成员变量
2)super.方法名()-----调用父类的方法
3)super()------------调用父类的构造方法
/
class Foo {
int value;
Foo(int value) {
this.value = value;
}
}
class Goo extends Foo {
int num;
/- 有两种解决方案,方案一为在父类中添加无参的构造方法.
- 方案二为在子类构造方法中显示调用父类的有参构造方法(常常使用),
- 这样可以保证父类的成员变量均被初始化,
*/
//Goo(int num) {this.num = num;}//父类没有提供无参的构造方法,则会出现编译错误。
Goo(int value, int num) {
super(value);
this.num = num;
}
}
/*
- 向上造型:
- 1)父类型的引用指向子类的对象
- 2)能点出来什么,看引用的类型
/
//向上造型的演示
public class UpTypeDemo {
public static void main(String[] args) {
Coo o1 = new Coo(); //父只能调父的
o1.c = 1;
o1.show();
Doo o2 = new Doo(); //子既能调子的也能调父的
o2.d = 1;
o2.say();
o2.c = 2;
o2.show();
Coo o3 = new Doo(); //向上造型
o3.c = 1;
o3.show();
/
* 当用父类型引用指向了子类对象后,java编译器会根据引用的类型(Coo),
* 而不是对象的类型(Doo)来检查调用的方法是否匹配。
*/
//o3.d = 2; //编译错误,能点出来什么,看引用的类型
}
}
class Coo{
int c;
void show(){}
}
class Doo extends Coo{
int d;
void say(){}
}
/**
final:最终的
1)修饰变量:变量不能被改变
2)修饰方法:方法不能被重写 意义在于:防止子类在定义新方法时造成的“不经意”重写。
3)修饰类: 类不能被继承但是final修饰的类可以继承别的类
*/
//final的演示
public class FinalDemo {public static void main(String[] args) { }}
final class Poo{}
//修饰类: 类不能被继承但是final修饰的类可以继承别的类
//class Qoo extends Poo{} //编译错误,final的类不能被继承
class Roo{}
final class Soo extends Roo{}
//修饰方法:方法不能被重写
class Noo{
void show(){}
final void say(){}
}
class Ooo extends Noo{
void show(){}
//void say(){} //编译错误,final的方法不能被重写
}
/*final可以修饰成员变量,也可以修饰局部变量:
-
final修饰成员变量:
-
1)声明同时初始化或者在构造方法中初始化
-
final修饰局部变量:
-
1)用之前初始化即可(不用可以不初始化)
*/
//修饰变量:变量不能被改变
class Moo{
final int a = 5;
final int b;
Moo(){
b = 5;
}void show(){
final int c;
//System.out.println©; //编译错误,使用之前必须初始化
//a = 55; //编译错误,final的变量不能被改变
}
}
public class Foo {
public int a; //所有
protected int b; //本,子,同包
int c; //本,同包
private int d; //本
void show(){
a = 1;
b = 2;
c = 3;
d = 4;
}
}
class Goo{ //private
void show(){
Foo o = new Foo();
o.a = 1;
o.b = 2;
o.c = 3;
//o.d = 4;
}
}
/*
在java语言中,子类可以重写(覆盖)继承自父类的方法,
即方法名和参数列表与父类的方法相同,但是方法的实现不同。
子类重写了父类的方法后,该重写方法被调用时
(无论是通过子类的引用调用还是通过父类的引用调用),运行的都是子类重写后的版本。
1.方法的重写(override):重新写、覆盖
1)发生在父子类中,方法名称相同,参数列表相同,方法体不同。
2)重写方法被调用时,看对象的类型。
/
//重写的演示
public class OverrideDemo {
public static void main(String[] args) {
/
* 重写遵循"两同两小一大"原则:一般都是完全相同的
* 1.两同:
* 1)方法名相同
* 2)参数列表相同
* 2.两小:
* 1)子类的返回值类型小于或等于父类的
* 1.1)基本类型和void时,必须相同
* 1.2)引用类型时,小于或等于
* 2)子类抛出的异常小于或等于父类的–异常之后
* 3.一大:
* 1)子类的访问权限大于或等于父类的–访问控制修饰符后
*/
}
}
//父类大,子类小
class Aoo{
void show(){}
double say(){return 0.0;}
Aoo get(){return null;}
Boo test(){return null;}
}
class Boo extends Aoo{
void show(){} //void时必须相同
double say(){return 2.2;} //基本类型时必须相同
Boo get(){return null;} //正确的,小于
//Aoo test(){return null;} //错误的,只能小于或等于
}
package oo.day04;
/**
重写与重载的区别----常见面试题
1)重写:
1.1)发生在父子类中,方法名相同,参数列表相同,方法体不同
1.2)遵循"运行期绑定",看对象的类型调用方法
2)重载:
2.1)发生在一个类中,方法名相同,参数列表不同
2.2)遵循"编译期绑定",看引用的类型绑定方法
*/
//重写与重载的区别
public class OverrideOverloadDemo {
public static void main(String[] args) {
//重写:看对象的类型 重载:看引用的类型
Eoo eoo = new Eoo();
Coo o = new Doo(); //向上造型
eoo.test(o);==父类型参数 子类–show
}
}
class Coo{
void show(){
System.out.println(“父类–show”);
}
}
class Doo extends Coo{
void show(){
System.out.println(“子类–show”);
}
}
class Eoo{
void test(Coo o){
System.out.println(“父类型参数”);
o.show();
}
void test(Doo o){
System.out.println(“子类型参数”);
o.show();
}
}
/**
1.static存在的意义就是不需要实例化某个类就可以调用.
被static修饰的成员变量和成员方法独立于该类的任何对象。
也就是说,它不依赖类特定的实例,被类的所有实例共享。
只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。
因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象。
2.静态的存在方法区中,属于类的直到程序停止才消失。静态的可以直接调用静态的,
而非new来访问格式:类名. 静态的不可以直接调用非静态的(实例变量和方法),非
静态可以直接调用静态的。
/
//static的演示
public class StaticDemo {
public static void main(String[] args) {
Joo o1 = new Joo();
o1.test();//a=1 b=1
Joo o2 = new Joo();
//静态变量:属于类,存在方法区中,只有一份
o2.test();//a=1 b=2
System.out.println(Joo.b); //2 常常通过类名.来访问
System.out.println(o1.b); //2 也可以通过对象.来访问
//Koo.say();
//在类被加载时自动执行,因类只被加载一次, 所以静态块也只执行一次
Loo o3 = new Loo();
Loo o4 = new Loo();
Loo o5 = new Loo();
}
}
class Loo{
/*
3)静态块:类实例化或者有静态初始化需求的时候才被加载,JVM加载类时会执行这些静态的代码块。
3.1)由static修饰
3.2)在类被加载时自动执行,因类只被加载一次, 所以静态块也只执行一次
3.3)何时用:常常用于初始化静态资源(图片、音频、视频…)
/
static{
System.out.println(“静态块”);
}
Loo(){
System.out.println(“构造方法”);
}
}
class Koo{
int a;
static int b;
void show(){
a = 1;
b = 2;
}
/*
2)静态方法:
2.1)由static修饰
2.2)属于类,存在方法区中,只有一份
2.3)常常通过类名.来访问
2.4)静态方法没有隐式的this传递,
所以静态方法中不能直接访问实例成员
2.5)何时用:方法的操作仅与参数有关而与对象无关时使用
调用一个静态方法就是“类名.方法名”,静态方法的使用很简单。一般来说,
静态方法常常为应用程序中的其它类提供一些实用工具所用
/
static void say(){
/
*静态方法没有隐式this传递,没有this意味着没有对象,
*而实例变量a必须通过对象点来访问,所以此处编译错误
*/
//a = 1; //编译错误
b = 2;
}
}
class Joo{
/**static:静态的
1.静态变量:
1.1)由static修饰
1.2)属于类,存在方法区中,只有一份
1.3)常常通过类名.来访问
1.4)何时用:所有对象数据都一样时使用
2.成员变量:分为实例变量和静态变量
1)实例变量:属于对象的,存在堆中,必须通过对象.来访问
2)静态变量:属于类的,存在方法区中,通过:类名.来访问也可以对象.来访问
3.static变量前可以有private修饰,表示这个变量可以在类的静态代码块中,
或者类的其他静态成员方法中使用(当然也可以在非静态成员方法中使用–废话),
但是不能在其他类中通过类名来直接引用,这一点很重要。
*/
int a;
static int b;
Joo(){
a++;
b++;
}
void test(){
System.out.println(“a=”+a);
System.out.println(“b=”+b);
}
}
代码块:
用{}括起来的代码。
根据{}的位置可以分为
局部代码块:方法中,局部位置,作用:限定变量作用范围和生命周期。
构造代码块:在类中方法外(成员位置),用{}括起来的代码。
每次调用构造方法执行前,都会执行构造代码块,
作用:把类中不同构造方法中相同的部分提取出来定义到构造代码块中,以后无论调用哪个构造方法都会执行相同操作。可以理解对对象初始化。
静态代码块:在类中方法外(成员位置),用{}括起来,用static修饰。作用:给类进行初始化。
代码块执行顺序:
静态代码块》构造代码块》构造方法
静态代码块:只执行一次
构造代码块:每次创建该类对象,调用构造方法就执行,先于构造方法。
被JVM装载->执行父类的相关代码->如果有静态初始化,先执行静态初始化,且只执行一次,以后即使有该类实例化,也不会再执行->如果有静态代码块,以与静态初始化一样的方式执行->如果有new语句带来的实例化,先为成员变量分配空间,并绑定参数列表,隐式或显式执行super(),即父类的构造方法,->执行非静态代码块-〉执行本类的构造函数-〉执行其他代码
下面通过一个案例进行解析:
public class DaiMaKuai {
static {
System.out.println(“大家好我是静态代码块!”);
}
{
System.out.println("大家好我是构造代码块!");
}
public DaiMaKuai(){
System.out.println("大家好我是构造方法!");
}
}
入口类:
package day08;
public class DaiMaKuaiDemo {
static {
System.out.println("河南科技大学!");
}
public static void main(String[] args) {
System.out.println("洛阳牡丹甲天下!");
//创建DaiMaKuai类对象
System.out.println("-------------------------");
DaiMaKuai dmk = new DaiMaKuai();
System.out.println("-------------------------");
DaiMaKuai dmk1 = new DaiMaKuai();
}
}
输出:
河南科技大学!
洛阳牡丹甲天下!
大家好我是静态代码块!
大家好我是构造代码块!
大家好我是构造方法!
大家好我是构造代码块!
大家好我是构造方法!
/**
1.接口:也是单根性继承的扩展(类只能继承一个)
1)是一个标准、规范-----制定方 遵守这个标准,就能干某件事-----API后
2)由interface定义:只能包含常量和抽象方法
3)接口不能被实例化
4)接口是需要被实现的,实现类/子类(遵循标准、规范的类):
必须重写接口中的所有抽象方法并且前面必须加public修饰
5)一个类可以实现多个接口,用逗号分隔.若既继承又实现时,应先继承后实现
6)接口可以继承接口
6.1)类和接口之间实现(implements)
6.2)接口和接口之间为继承(extends)
6.3)类和类之间为继承(extends)
2.定义接口语法: interface +接口名{
常量(public static final)可省略也可以写public
抽象方法 (public abstract)可省略
}
*/
public class InterfaceDemo {
public static void main(String[] args) {
//Inter5 o1 = new Inter5(); //编译错误,接口不能被实例化
Foo o2 = new Foo();
Inter6 o3 = new Foo(); //向上造型
Inter5 o4 = new Foo(); //向上造型
}
}
//接口间的继承
interface Inter5{ void a();}
interface Inter6 extends Inter5{ void b();}
class Foo implements Inter6{public void b(){}public void a(){}}
//接口的多实现
interface Inter3{ void a();}
interface Inter4{ void b();}
abstract class Doo{ abstract void c();}
class Eoo extends Doo implements Inter3,Inter4{//先继承后实现
public void a(){}
public void b(){}
void c(){}
}
//接口的实现
interface Inter2{ void a(); void b();}
class Coo implements Inter2{ public void a(){} public void b(){}}
//演示接口的基础语法
interface Inter1{
public static final double PI=3.14159;
public abstract void show();
int NUM=2; //默认public static final
void say(); //默认public abstract
//int num2; //编译错误,默认常量,必须声明同时初始化
//void sayHi(){} //编译错误,默认抽象方法,不能有方法体
}
//求一组图形中的最大面积
public class ShapeTest {
public static void main(String[] args) {
//Shape s1 = new Shape(); //编译错误,抽象类不能被实例化
Shape[] shapes = new Shape[4]; //创建Shape数组对象
shapes[0] = new Circle(1); //向上造型
shapes[1] = new Circle(2);
shapes[2] = new Square(1);
shapes[3] = new Square(2);
maxArea(shapes);
}
public static void maxArea(Shape[] shapes){ //求最大面积
double max = shapes[0].area(); //最大面积
int maxIndex = 0; //最大面积下标
for(int i=1;i<shapes.length;i++){
double area = shapes[i].area();
if(area>max){
max = area;
maxIndex = i;
}
}
System.out.println(“最大面积为:”+max+",所在索引为:"+maxIndex);
}
}
/**
抽象类:
1)由abstract修饰
2)包含抽象方法的类必须是抽象类
没有抽象方法的类也可以声明为抽象类–我愿意
3)抽象类不能被实例化(new对象)但是可以声明抽象类数组Shape[] shapes = new Shape[4];
4)抽象类都是需要被继承的,子类:
4.1)重写抽象类中的所有抽象方法
4.2)也声明为抽象类—一般不这样做
5)抽象类的意义:
5.1)父类的意义:
5.1.1)封装所有子类共有的属性和方法
5.1.2)为所有子类提供一种公共的类型–向上造型( 抽象类名 引用=new 子类();
5.2)可以包含抽象方法,由子类来做不同的实现,但是入口一样(父类都能点出来/方法名)
/
abstract class Shape{ //抽象类-不完整
protected double c; //周长
/*
抽象方法:也可以将抽象方法理解为不完整的方法。
1)由abstract修饰
2)只有方法的定义,没有方法的具体实现(连大括号都没有)
/
public abstract double area(); //抽象方法-不完整
}
class Square extends Shape{
public Square(double c){
this.c = c;
}
public double area(){ //重写–变不完整为完整
return 0.0625cc;
}
}
class Circle extends Shape{ //0.0796
public Circle(double c){
this.c = c;
}
public double area(){
return 0.0796c*c;
}
}
/**
可以总结出如下几点抽象类和接口的区别:
1.一个类只能继承一个抽象类,但可以实现多个接口。
2.抽象类中可以包含抽象方法和非抽象方法,而接口中的所有方法均为抽象的。所以的变量都是常量必须声明时初始化。
3.子类继承抽象类必须实现抽象类中所有抽象方法,否则子类也必须是抽象类。
而子类实现接口则必须实现接口中的所有抽象方法。
设计规则:
1)将公共的属性和行为,抽到父类中
2)所有子类行为都一样,做成普通方法 所有子类行为不一样,做成抽象方法
3)符合既是也是的规则,使用接口(部分子类共有的行为)
4)将程序的任务,流程,步骤写到测试类中
*/
/**
static final:修饰的成员变量称为常量
1)必须声明同时初始化
2)由类名点来访问,并且不能改变
3)建议:常量名所有字母大写
4)常量在编译期被直接替换为具体的值–效率高可以节约不必要的开支
/
//static final常量的演示
public class StaticFinalDemo {
public static void main(String[] args) {
System.out.println(Aoo.PI); //通过类名点来访问
//Aoo.PI = 3.1415926; //编译错误,常量不能被改变
/
1.方法区中加载Boo.class
2.num2存储在方法区中
3.到方法区中获取num2的值并输出
*/
System.out.println(Boo.num2);
//在编译期被直接替换为具体的值,效率高
//相当于System.out.println(100);
System.out.println(Boo.NUM);
}
}
class Boo{
public static final int NUM = 100; //常量
public static int num2 = 200; //静态变量
}
class Aoo{
public static final double PI=3.14159;
//public static final int NUM; //编译错误,必须声明同时初始化
}
/**
成员内部类:
1)类中套类,里面的称为内部类类称之为Inner,外面的称为外部类称之为Outer
2)内部类通常只服务于外部类,对外不具备可见性(不能实例化在其它类中)
一般情况下,Inner对象会在Outer对象中创建(构造方法或其他方法);
3)内部类对象通常是在外部类中创建
4)内部类中可以直接访问外部类中的成员(包括私有的)
内部类中有一个隐式的引用指代创建它的外部类的对象
外部类名.this.----eg: Mama.this.
*/
//成员内部类演示
public class InnerClassDemo {
public static void main(String[] args) {
Mama m = new Mama();
//Baby b = new Baby(); //编译错误,内部类对外不具备可见性
}
}
class Mama{
private String name;
Baby createBaby(){
Baby b = new Baby();
return b;
}
class Baby{
void showMamaName(){
System.out.println(name);
System.out.println(Mama.this.name);
//System.out.println(this.name); //this为当前对象,即Baby类对象,而Baby类没有name属性
}
}
}
/**
1.多态:(都造了型向上造型)
1)多态的意义:
1.1)同一类型的引用指向不同对象时,有不同的实现 ----行为的多态: cut()
1.2)同一个对象被造型为不同类型时,有不同的功能 ----对象的多态: 我
2)向上造型:
2.1)父类型的引用指向子类的对象
2.2)能向上造型为的类型: 父类、所实现的接口
2.3)能点出来什么,看引用的类型 重写方法被调用时,看对象的类型
3)强制类型转换,成功的条件:
3.1)引用所指向的对象,就是该类型
3.2)引用所指向的对象,实现了该接口
4)强转若不符合如上两个条件,则发生类型转换异常,(Class cast Exception)
建议:强转之前先通过instanceof来判断,而后再强转
instanceof判断引用的对象是否是某类型,返回boolean型结果
强转成功的条件就是它为true的条件
cut()行为就是多态的
人 p1 = new 理发师();
人 p2 = new 外科医生();
人 p3 = new 演员();
p1.cut(); //剪发
p2.cut(); //开刀
p3.cut(); //停止表演
abstract class 人{
abstract cut();
}
class 理发师{
cut(){ 剪发 }
}
class 外科医生{
cut(){ 开刀 }
}
class 演员{
cut(){ 停止表演 }
}
*/
//多态的演示
public class MultiTypeDemo {
public static void main(String[] args) {
Aoo o1 = new Boo(); //向上造型
Boo o2 = (Boo)o1; //o1指向的对象就是Boo类型
Inter1 o3 = (Inter1)o1; //o1指向的对象实现了Inter1接口
//Coo o4 = (Coo)o1; //类型转换异常
if(o1 instanceof Coo){ //false
Coo o5 = (Coo)o1;
}
}
}
interface Inter1{}
class Aoo{}
class Boo extends Aoo implements Inter1{}
class Coo extends Aoo{}
/**
匿名内部类:
1.如果在一段程序中需要创建一个类的对象(通常这个类需要实现某个接口或者继承某个类),
而且对象创建后,这个类的价值也就不存在了,这个类可以不必命名,称之为匿名内部类。
1)想创建一个类的对象,并且对象只创建一次, 该类不必命名,称之为匿名内部类
2)匿名内部类中访问外面的变量,该变量必须是final的
3)内部类有独立的.class
2.匿名内部类的结构:Inter2 o2 = new Inter2(){ };
2.1)用匿名类所实现的接口或所继承的父类类型声明的引用;
2.2)new 后面的为匿名类所要实现的接口或继承的父类;
2.3)小括号()中为构造方法参数;
2.4)大括号中为匿名中定义的成员变量或方法。
(如果父类中有抽象方法子类必须重写抽象方法)
/
//匿名内部类演示
public class NstClassDemo {
public static void main(String[] args) {
//Inter2 o1 = new Inter2(); //编译错误,接口不能被实例化
/*
1.创建了Inter2的一个子类,没有名字
2.为该子类创建了一个对象,名为o1
3小括号()中为构造方法参数
4.大括号中的为子类的类体(为匿名中定义的成员变量或方法。)
*/
Inter2 o1 = new Inter2(){ };
//1.创建了Inter2的一个子类,没有名字
//2.为该子类创建了一个对象,名为o2
//3.大括号中的为子类的类体
Inter2 o2 = new Inter2(){
};
final int num=250;
/*o3为Inter3子类的对象
* run()为Inter3子类的方法
*/
Inter3 o3 = new Inter3(){
public void run(){
System.out.println("abc");
System.out.println(num); //num必须是final的
}
};
/*o3为Inter3子类的对象,run()为Inter3子类的方法
* o3.run()为调用子类的方法
*/
o3.run();
}
}
interface Inter3{ public void run();}
interface Inter2{}
/**
4.面向对象三大特征:封装、继承、多态
1)封装:
1.1)类:封装对象的属性和行为
1.2)方法:封装具体的功能的实现
1.3)访问控制修饰符:封装访问的权限
2)继承:
2.1)作用:有利于代码的复用
2.2)父类/基类:共有的
子类/派生类:特有的
2.3)子继承父后,具有:父的+子的
3)多态:
3.1)意义:行为的多态、对象的多态
3.2)向上造型、强制类型转换、instanceof
3.3)表现形式:
重写、重载
*/