面向对象编程
面向对象指以属性和行为的观点去分析现实中的事务
在面向对象时只分析该对象是否具备该属性和行为
类名当由多个单词构成首字母必须大写
当成员变量由多个单词构成时,第二个单词必须大写,成员方法名也一样
引用变量主要用于记录对象在堆区的内存地址信息,便于下次访问
类的成员变量初始值通常省略不写
可变长参数
/*
编程实现可变长参数的使用
*/
public class ChangeArgument{
//将name参数看成数组,即可以为0-n个参数
//当不确定一个参数传入的数量时使用
public void argument(String... name){
for(int i=0;i<name.length;i++)
System.out.println(name[i]);
}
public static void main(String[]args){
ChangeArgument ar=new ChangeArgument();
ar.argument("hi","hjdhd","jdidi");
}
}
当我们自己写了构造方法,编译器则不提供默认的构造方法
- 构造方法的价值在对象实例化的同时给对象赋值
this关键字
- 若在构造方法中出现this 表示正在构造的对象
2.若在成员方法中出现this 表示正在调用的对象
this关键字本质上为当前类类型的引用
在成员方法中调用成员变量没有写"对象."实际上是隐藏了this.(this为该对象的引用,可以代表当前对象)
3.当函数参数和属性名同名,用this强调区分
4.this 可以作为方法的返回值返回正在调用 的对象(用的不多)
5.在构造方法的第一行可以调用本类中的其他构造方法(了解,开发中用的不多)
对象只声明没有实例化会出现空指针异常
代码的拆分
将main单独写在测试类中
将程序拆分成功能类和测试类,编译测试类的时候,会将功能类一起编译
封装
acwing 特辑
package可以认为写的是代码的文件路径
每一个程序里面只能定义一个public class
procted 表示只能在当前类的子类中访问
对象的多态性:同一个类的不同对象进行同样调用同样的行为,但其表现不同,(子类和父类调用同一个行为时存在)
static关键字
当用static修饰时,成员变量由对象层提高到类层,被所有对象共享,,该成员变量随着类的加载准别就绪,和创建对象无关
/*
探究关键字构造块 的使用
*/
//当需要在执行构造方法体之前做一些准备工作时,可以将准备工作写在构造块中
//没创建一次对象都会执行一次构造块
//静态代码块,随着类的加载执行,只会执行一次,
//当需要在执行代码之前随着类的加载做一些准备工作,就编写在静态块中
public class BrickTest{
{
System.out.println("我是一个构造块");//该构造块会在构造方法之前调用
}
//定义一个构造方法
public BrickTest(){
System.out.println("我是一个构造方法!");
}
public static void main(String[]args){
BrickTest br=new BrickTest();
BrickTest be=new BrickTest();
}
}
在次认识main方法
/*
再次认识main方法
*/
//该main方法是java虚拟机在调用
//传递方法:在编译成class文件后,再次解释时 将需要传递的参数跟在类名后面
public class MainTest{
public static void main(String[]args){//main方法的参数为字符串数组
System.out.println("args数组的长度为"+args.length);
System.out.println("参数为:");
//注意:如果没有传入参数则一下打印代码不会被执行
for(int i=0;i<args.length;i++)
System.out.printf("hello");
}
}
对于构造函数的封装----重要
/*
编程实现SingleyonTestL类对Singleton类的测试,要求在main中只能得到该类的一个对象
对构造方法的封装
*/
class Singleton{
//封装构造方法
private Singleton (){
}
//将该对象设置成static 直接由类名调用实现和外界的交互
//防止外界直接调用,将对象报废,将其封装
//饿汉式--直接创建对象
private static Singleton pr1 =new Singleton();//在类内构造
//懒汉式--先赋值为空
private static Singleton pr1=null;
//提供封装对象的外部访问的公有化方法
//如果不加static 外界还是无法访问(因为外界没有对象)
public static Singleton getInstance(){
//return pr1;//饿汉式
//懒汉式--调用该方法时才创建对象
if(null==pr1)
pr1=new Singleton();
return pr1;
}
public class SingletonTest{
public static void main(String[]args){
//该处类内没有权限调用封装的构造方法
//Singleton pr=new Singleton();
Singleton pr=Singleton.getInstance();
Singleton pr2=Singleton.getInstance();
System.out.println(pr2==pr);//返回true 2个对象为同一个
}
}
一个类 对外提供且只提供一个对象,这种类被称为单例类,设计单例类的流程和思想被称为单例设计模式
举例:window的任务管理器只提供一个窗口
继承
继承的特点
- 子类不能继承父类的构造方法和私有方法 , 但私有成员可以被继承但不能被访问(生活经历)
2.无论使用什么方法调用子类对象时,都会调用父类的无参构造来初始化父类中继承成员的变量,相当于在子类的构造方法的第一行增加了super()
3.除了有相同的特征和行为外,还不许满足逻辑关系:子类 is a父类,也就是不能滥用继承
4,java语言中不支持多继承,只支持单继承,一个子类只能有一个父类,一个父类可有多个子类
方法重写
方法重写的现实意义:当需要用方法打印子类的特征而只有 父类中的show函数,子类调用后也只能打印子类继承自父类的特征,而不能打印子类特有的特质
,在此情况下,子类进行show函数重写,子类调用show函数,则是调用重写后的show函数
添加@override 注解 表示说明下面方法是对父类方法的重写,没有构成重写则会报错哦
方法的重写原则
- 要求方法名相同.参数列表相同以及返回值类型相同。从java5开始允许,当父类返回父类类型时,子类返回子类类型
对修饰符的要求
-
要求重写方法的访问空间不能变小,可以变大或者相同
-
要求方法不能抛出更大的异常
IDEA
src 源代码的简写
**该目录模仿引用Scanner 的目录 java.util.Scanner;
这执行代码之前会先将代码加载到内存的方法区 ,意味着在执行main方法之前会先执行静态代码(随着class文件生成时执行,和static变量一个道理),当执行构造函数之前构造块会优先执行,然后执行构造方法里面的构造方法块
执行顺序:静态代码-->构造块--->构造方法块
//测试构造方法体 构造快 静态代码块的执行顺序
public class SuperTest {
{//在构造方法之前执行
System.out.println("我是一个构造块");
}
//在生成class 文件时就随类加载执行
static {
System.out.println("我是一个静态代码块");
}
public SuperTest(){
System.out.println("我是一个构造方法体");
}
public static void main(String[]args){
}
}
拓展
//SubSuperTest的子类
//探究在子类和父类同时有静态代码块 构造块 构造方法体时
//当创建子类对象时的执行顺序
//在加载类的时候必将先加载父类然后再加载子类 有父才有子
//除了这三个代码块的顺序外 还有在调用子类的构造方法之前还必须调用父类的构造
public class SubSuperTest extends SuperTest {
{//在构造方法之前执行
System.out.println("-----我是一个构造块");
}
//在生成class 文件时就随类加载执行
static {
System.out.println("-------我是一个静态代码块");
}
public SubSuperTest(){
System.out.println("-----------我是一个构造方法体");
}
}
public class SuperTest {
{//在构造方法之前执行
System.out.println("我是一个构造块");
}
//在生成class 文件时就随类加载执行
static {
System.out.println("我是一个静态代码块");
}
public SuperTest(){
System.out.println("我是一个构造方法体");
}
public static void main(String[]args){
SubSuperTest ar=new SubSuperTest();
}
}
执行结果
权限修饰符和包的定义
关于访问权限的设定规律
-
public 成员可以在任意位置使用
-
private成员只能在本类内部使用
-
通常情况下,成员方法都使用private关键字修饰 成员方法都使用public 修饰
关于package
import导入静态成员变量
final的使用
final修饰变量的作用
- final修饰成员变量体现在该变量必须被初始化且不能被改变
理解:该变量不能被操作,即不能被赋值为默认值和后期手动初始化
final变量的初始化
//测试final对成员变量的作用
//对final成员变量初始化的方法:
//1. 在构造方法中对成员变量初始化
//2. 在构造块中对成员变量初始化
//3.final的显式初始化
public class FinalTest{
//显式初始化
private final int age ;//如果不赋初始值构造方法不会将其赋值
//{
//age=45;//构造块中初始化
//}
public FinalTest(){//也可以在构造方法体中对final变量初始化
age=34;
}
public static void main(String[]args){
FinalTest fi =new FinalTest();
}
}
关于static 和非static之间访问的权限的解释
static可以访问static 不能访问非static:
static 修饰的在类加载时(即生成class)时就已经准备好,此时可能 非static还没有被编译,非static 在创建对象时才被编译
非static可以访问非static也可以访问static修饰的
在编译非static 修饰的时,static一定被准备好了,因为其在类的加载时就已经准备好了
java程序编译过程,先由编译器编译成class文件,即字节码,然后由java虚拟机完成编译
static的相关变量或则静态代码块,在随着类的加载编译时就会编译完成,
类的加载,即java虚拟机加载class 文件加载类,而一般的变量要等到创建对象时才完成**
多态
多态的前提是有继承
idea: 快捷键
- main 回车直接生成main方法
- sout 回车生成 System.out.println();
3.ctrl+d 可以复制当前行 - alt+shif+上下方向键 可以移动代码
静态方法看是可以以重写,但不是真正意义上的重写
因为方法重写主要是为了使用多态,而多态的使用,需要进行对象的指向
而静态方法隶属于类层级,在创建对象之前就存在,所以静态方法不能重写
多态的特点
1.静态方法在编译阶段和运行阶段调用的都是父类中的版本
静态方法 的调用只取决于这个对象隶属的类型和所指向的对象无关
对于向上转型和向下转型2种方式调用的总结:
-
不管是转为父类类型还是转为子类类型都满足子类和父类之间继承的基本规律
-
当非static 方法在子类中重写时,向上转型和向下转型都是调用复写后的方法
-
当static 方法重写调用的都是父类中的static方法(这个向下转型还没有确定)
在进行类型的强制类型转换时,用instanceof判断 避免出现类型转换异常
核心理念:父类类型的引用指向子类类型的对象
多态的实际意义
多态使用场合之一:通过参数传递形成多态
抽象方法和抽象类
抽象类不能实例化对象的原因说明
因为真正意义上的抽象类中有抽象方法,而抽象方法没有方法体,用new出来的对象去调用抽象方法则没有实际意义,为了防止程序员犯这样的错位,所以这样设计
有抽象方法的类才是真正意义上的抽象类,抽象类中没有抽象方法也不报错,但建议带有抽象方法
抽象类的意义在于被继承
多态的使用场合二:直接在方法体中使用抽象类的引用指向子类类型的对象
多态的实际意义:
屏蔽不同子类的差异性实现通用性的编程
抽象方法要定义成public否下无法被重写
子类的私有方法和构造方法无法被继承
final修饰方法不能被重写可以被继承,abstract修饰的方法一定要被重写,所有两者不能共存(可能不准确)
static 和abstract也不能共存(可能不准确)
接口
java9中允许接口中出现私有方法
接口中的常量和抽象方法的修饰符固定可以省略,但建议不要省略
接口的存在意义
当一个类可以有多个父类时,就无法表示了,因为java无法多继承,如 黄金 is a 金属 也是 is a 货币, 但提供了接口,一个类可以继承多个接口,就为
这种情况的继承提供了可能
接口的实际生活意义,可以理解为赋予了一项新的功能
总结 使用抽象类和接口然后用类去继承抽象类或者实现接口,之所以不直接new 子类的对象而去 形成多态,是为了在传输对象时更方便
传对象时只需要一个函数来接收对象就可以了**
类和接口之间的区别
内部类
其中匿名内部类用的最多
普通(成员)内部类
普通内部类的格式
普通内部类的对象的创建
内部类的使用方式
当 函数参数名和类的成员变量名同名时----局部变量优先原则---
内部类访问原则
//内部类中访问原则
public void show2(int cent){
System.out.println("形式参数cnt="+cent);//局部变量优先 先使用参数
System.out.println("内部参数cnt="+this.cent);//打印内部参数
System.out.println("外部参数cnt="+NormalOuter.this.cent);//打印外部参数
}
静态内部类
静态内部类的创建方法
内部类的访问原则
//snt同时在内部类和外部类中
public void show2(int snt){
System.out.println(snt);//参数和成员变量相同--就近原则
System.out.println(StaticInner.snt);//内部类为static 推荐用类名访问
System.out.println(StaticOuter.snt);//外部类为static 用类名访问
}
}
局部内部类
局部内部类类名没有修饰符
局部内部类的使用原则概述:局部内部类只能在当前方法体的内部使用
所以只能在当前方法体内部声明引用指向内部类的对象
局部内部类的使用
因为该内部类在外部类的方法里面,要运行该方法才能运行该内部类,所以必须先创建外部类的对象,然后调用该方法才可以使用该内部类
该处定义的变量编译器默认为final,可以省略但建议不要省略*
局部内部类的使用方式
https://www.cnblogs.com/dolphin0520/p/3811445.html
回调模式
回调和匿名内部类没有搞定
枚举
枚举类
生活中有一些东西只有特定的几个数值,并且这些数值不可改变,比如一年的四季,方向,可以用枚举类来实现
和单例设计模式的联系:和单例设计模式很像,单例设计模式有且只有一个对象,而枚举类有且只有几个对象(具体的个数视情况而定),并且不可更改
该过程的内存分析不理解
//实现方向的枚举类,要求对象个数有限并且不可更改
//所有方向:向左 向右 向上 向下
public class Direction {
private final String dec;
//这里的对象(属性)都要封装,通过get方法得到,这里先不封装
public static final Direction UP=new Direction("向上");
public static final Direction Down=new Direction("向下");
public static final Direction LEFT=new Direction("向左");
public static final Direction RIGHT=new Direction("向右");
// public static final String dec="向上"; 如果使用该方式初始化,dec数值都是一样的
private Direction(String dec ){
this.dec=dec;
}
public String getDec() {
return dec;
}
public static void main(String[] args) {
//只能得到这固定的四个对象并且不可更改
Direction re=UP;
Direction ra=RIGHT;
Direction rc=LEFT;
Direction rd=Down;
}
}
用内部类来描述枚举过于繁琐,代码有很多都重复
由此而生了一种全新的数据类型---枚举数据类型 (引用数据类型)
使用枚举数据类型改良枚举类
将枚举看成特殊的类,将注解看成特殊的接口