文章目录
一、面向对象思想
- python、java(万物皆对象)对比c语言有垃圾回收机制对局部变量进行定期回收、java的底层是c;
面向对象的开发:就是在不断的创建对象,使用对象,指挥对象;
面向对象的设计:管理和维护对象之间的关系;
面向对象的特征:封装、继承、多态;
面向过程思想:c语言,每一环关系紧密,前后相关,一步一步的实现,适合简单的需求开发;
适合写系统(死的业务功能)不适合写复杂逻辑;
-
类与对象的关系:属性(该实物的描述信息)
行为(该类行为)、举例;
1、private修饰
-
private私有访问权限修饰符,基本上就是默认的对所封装的属性进行修饰
-
以后我们开发项目时需要不断的声明类,在类中需要封装属性和行为,但是针对某一些属性,我们需要保护起来,不希望直接对外界提供访问,所以要用private修饰在别的类和模块是不能被访问到的。只有在本类中才能被访问到。
-
需要针对每个私有属性封装get和set方法;get与set方法快捷键 alt+insert(按shift键进行全选)选中并生成;以及构造方法都可以此快捷键生成。
想要很便捷的查看数据就要重写toString方法;(也可以在alt+insert生成)
-
this 指向的是本类中的实例变量,把局部变量(形参)赋值给本类中的(私有)变量;
-
创User [ ] Users = new User[n];
二、内存
1、Jvm虚拟机开辟空间
-
栈内存:(主函数(变量),需要调用的方法)在jvm内存中所有方法无论是静态方法还是普通方法(实例方法)都在栈中;
-
堆内存:①引用数据类型(数组)声明的变量地址在栈内存中、而创建、赋值等操作在堆内存定义类中的实例变量,一定在堆内存中开辟空间因为new出来的部分一定在堆中;
②局部变量:是存在于方法体内部的的变量(包含类参数)
-
基本数据类型直接开辟在栈中;
string str = “hello”
str 地址在栈中;
“hello”存放在方法区的常量池中;
string str1 = new string(“hello”)中str1存与栈中;
new string 在堆中;“hello”在方法区的常量池中
结论:str与str1指向不同,str直接指向常量池,而str1指向堆内存再指向常量池中的hello;
双等号比较的并不是数值而是指向地址;
equals比较的是字符串的地址
-
方法区内存:一般存放代码片段( java源文件编译后的字节码文件.class)
常量池存放字符串数据;
2、代码执行过程对应内存位置
-
单对象情况下:
-
两个对象的情况下
-
两个变量名指向同一个对象,是使用的同一个堆内存地址
-
当一个对象作为参数,传递到方法当中时,实际上传递进去的是对象的地址值
-
当对象作为返回值时
三、封装
隐藏对象的属性和实现细节,仅对外提供公共访问方式,(隐藏细节,提高复用性、安全)
四、内容
1、构造方法
- 给对象数据进行数据初始化;
- 方法名与类名相同;没有返回值类型,连void都没有,没有具体返回值;
- 不提供则系统默认;提供了(不论有没有参数的)系统都不再提供无参构造方法;构造方法可重载
- 构造方法是就是创建实例时要调用的方法系统会默认一个无参构造;如果自定义的编写一个有参构造那么就要用重载的方法在给一个无参构造避免不能实例化对象,有参构造可以创建对象时就对对象进行赋值;(直接参数带入,省得用set方法设置对象属性了。)
与对构造方法重载和加入set、get方法一样,
想要很便捷的查看数据就要重写toString方法;(也可以在alt+insert生成)
2、静态关键字
-
静态关键字:1、static,可以修饰方法、属性,不能修饰类;
-
属性上:被静态关键字修饰的方法、属性可以成为类级别的元素,会随着类的加载而加载;
调用上:(可以通过类名直接调用该方法或者用对象去调用,而普通方法必须需要实例化对象调用; 内存上:①(在方法体内的变量是局部变量是不能用static来修饰的。)静态变量会随着类的加载而加 载,②在jvm解析字节码文件时候该静态变量的空间就会被开辟 ,静态变量的内存空间开辟 在方法区里;③静态属于类称为类变量;静态方法存储与方法区的静态区;
-
分类
成员变量:实例变量、静态变量;
局部变量:方法体内部的变量(包括参数中的变量)
- 静态代码块:在类加载时就会被执行的语句体;在执行过程中:静态代码块会在主函数执行之前被执行,只有在类的首次加载时静态代码块才会被执行;静态方法中没有this关键字;静态方法只能访问静态的成员变量的静态的成员方法;
- main方法是静态的;public被jvm调用访问权限足够大;main是一个通用名不是关键字但可被jvm识别
五、继承与派生
1、继承
-
多个类中的相关属性以及功能进行继承操作;public class B extends A {}
-
继承父类中所有方法(私有方法可继承但是无法访问)和属性,只能继承一个父类, 支持多层继承不允许多继承;如果父类方法不能满足需求,可以对该方法进行重写(覆盖);
-
一个类什么都没继承时,默认继承(超类、祖宗类)object类
-
只要子类和父类有同名方法就构成重写;@override可有可无;
super.方法名表示指向父类,完全继承父类的方法的逻辑结构;如果重写就把该行删除
-
优点:提高复用性、维护性
缺点:类之间产生了耦合关系,会降低程序的独立性与效率;
-
子类不能继承父类的构造方法,但可通过super去访问父类构造方法;
不要为了部分方法而去继承;
-
在子类中访问一个变量:子类局部范围→子类成员→父类成员范围→报错(不能找父类的父类的父类。)
-
通过子类对象给父类的属性赋值:通过子类继承父类的有参构造(别忘了进行无参)构造的补充,通过有参构造来实例化子类对象:super(属性1、2)
2、super关键字:
-
super与this很像:this代表本类对象的引用,
super代表父类存储空间的标识,理解为父类引用;
-
用法:this/super.成员变量/方法 this/super{….}访问构造方法
-
使用构造时super或this语句一定要放在第一条语句处,否则出现父类数据多次初始化(本类其他构造会先使用父类的构造);
3、重写
- 父类私有方法不能被重写;
- 重写父类的方法时(权限>=只会变大)
- 父类静态方法,子类也只能使用静态方法进行重写。
- 重载overload:一个作用域内,可以改变返回值类型。
4、重载与重写的区别:
一、重写:从字面上看,重写就是 重新写一遍的意思。其实就是在子类中把父类本身有的方法重新写一 遍。注意子类函数的访问修饰权限不能少于父类的。权限需变大
1.发生在父类与子类之间;
2.方法名,参数列表,返回类型(除过子类中方法的返回类型是父类中返回类型的子类)必须相同;
3.访问修饰符的限制一定要大于被重写方法的访问修饰符(public > protected > default > private);
4.重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。
二、重载:在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但不能通过返回类型是否相同来判断重载。
面试时,问:重载(Overload)和重写(Override)的区别?
答:1. 方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。
2. 重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间;
3. 重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求,不能根据返回类型进行区分
5、多态
面向对象最重要的一个特征
-
程序的许多地方都会体现出多态;
-
必须要有父子关系的体现,是在不同时刻体现不同的状态 ,父类的引用接收子类对象;父类引用接收子类对象。父类 对象 = new 子类();父类对象即可使用子类的方法;
强转:父类 用来接收的对象 = (父类)子类对象: 子类对象强转为父类对象;
-
做开发时目的时解除类与类之间的耦合/(模块与模块之间的耦合)
不能面向具体编程要面向抽象编程;
-
引用类型的强转(向下转型)也是一种多态
-
多态机制分为编译与运行阶段:编译阶段看左边,编译时需要看调用的方法在父类中是否存在;
运行阶段看右边;我们实际new出来的对象是子类对象,最终执行的也是子类方法;由上可知:出现
父类对象向子类对象强转时,只要是父子关系强转编译时就不会报错,但是运行时(无父子关系)或 (子类向父类转)都会报错;
故:强转前做个判断(A. instanceof B)看A是否属于B再进行强转,避免异常; -
静态方法(类级别)同名时不能算作方法的重写,重写(调子类)静态方法时,编译看左边,运行看左边,是类级别的,不能体现重写的性质;
-
多态在以后开发中的作用:如果不使用多态,使用重载,在程序迭代
时需要修改程序,这样违背了模式中的开闭原则(OCP对拓展开放的对修改关闭):在写程序时避免 在源代码上进行修改;这样修改的部分在别的类调用时出现错误;
代码思想;为了使不用修改原来写好的代码,需要新增子类时依旧可以使用原来的类来创建对象以及正常使用就要用到重写以及多态的设计思想;
如下代码:
public class Person {
public void receive(Mwssage message){
message.Getmessage();
}
}
public class Mwssage {
public void Getmessage(){
System.out.println("null");
}
}
public class Ding extends Mwssage {
public void Getmessage() {
System.out.println("接受的是叮叮的消息!");
}
}
public class Test2 {
public static void main(String[] args) {
Person person = new Person();
person.receive(new QQ());
person.receive(new Wechat());
person.receive(new Ding());
}
}
代码解析:
person类下有一个接受消息receive方法;该方法时以messsage类对象作为参数
message类中中有一个getmessage方法;
当我们需要增加新的功能时,创建一个新的子类继承message类并重写getmessage方法实现多态
测试时只需要创建原person类的对象就可以用receive方法来传入子类的引用即可;
多态好处 案例:主人喂养宠物;
8、重载不算多态(没有体现父子关系)
六、抽象类
1、抽象类
-
抽象类abstrat是最顶级的表现,接下来就是类,接下来就是对象,
我们如果想要创建对象,只能通过class定义的类去创建,抽象类不能创建对象;
-
abstart class 类名。 public abstract void eat(); 抽象类不一定有抽象方法,可以有普通方法/成员变量,或者静态的方法/成员变量;有抽象方法的类一定是抽象类;
-
抽象类是不能实例化对象的,因为抽象类的下一级是class;
作用是用来被子类继承的(唯一作用)
-
抽象方法没有方法体的,不用提供方法本身的具体的实现,当子类继承了抽象类的抽象方法后必须要在子类中重写;抽象方法本身就是模糊的不用提供具体的实现
-
可以由抽象的父类引用子类的对象来使用自身的方法;
-
抽象类允许存在构造方法(不可以实例化对象但有构造方法),抽象类的构造函数是用来给子类继承在使用super来指向父类构造方法使用的(可用来访问抽象类的相关属性,通过构造的方式给抽象类中的属性赋值);
2、final常量
- 性质
①final来修饰的类可以正常的调用方法、创建对象,但是该类不能用来继承;
②被final修饰的基本数据类型要在定义时就初始化且之后不能修改;
③如果是引用数据类型变量的引用不能指向别的内存地址;
④fianl修饰的方法,被子类继承后不能被重写;可以修饰类、成员变量、局部变量、方法(静态、实例方法)
面试题: final关键字能否修饰抽象类?
不可以,fianl修饰后的效果与抽象类的唯一作用相冲突
1、final与abstrat不能同时出现;冲突
2、private与abstrat冲突;
3、static与abstract无意义;
- 常量定义: Public static final String NAME
1、用static修饰是使常量变成一个类级别的,随着类加载而初始化避免每次实例化对象重新为常量在堆中加载空间,从而节省空间;
2、final是使得常量后期不可改变;
3、常量名称(所有字母都大写与单词之间用_下划线隔开);
- 案例:三个人在三家银行存取钱以及转账,使用继承多态相关知识模拟出相关行为;(已做)面3-2
七、接口
1、接口定义
- (一种规范)以后的程序设计都是基于接口进行开发,因为声明方法时,我们都需要这个方法的多变性, 而随着业务的改变针对这个接口的具体实现;
- 从持久层开始写接口;为了体现事物的拓展性。
- 接口是一种引用数据类型,在类加载过程中也会生成对应的字节码文件。
2、接口性质
-
接口其实就是抽象类(或抽象类的一种但是要更严格一点(不能有成员变量)),接口中的方法只能是抽象方法;接口的所有方法都是没有方法体的。
-
通过interface定义接口;(在idea中是大写绿色I的标志)
-
接口中的成员:只能定义抽象方法、常量;
-
定义方法是可以把public abstract void fun()省略为void fun()
由于接口中的都是抽象方法所以前面的可以省略。
-
接口作用:在设计模式中,我们要面向接口开发,接口+多态可以实现程序的可拓展性灵活性
-
在接口中是允许有多继承的、也支持多实现;
-
接口和抽象类类似,不能实例化对象,是用来被子类实现(类似与继承)的;
实现的关键字:implements
当子类实现接口之后:一定要对接口中的所有抽象方法进行重写!
用多态的方式创建对象(父类对象对子类的引用) -
接口中的成员变量:只能默认为常量,自动忽略Public static final
接口无构造方法,只能拓展功能,没有具体实现存在。
3、接口与类的关系:
- 类与类,继承关系;只能是单继承不能是多继承,
- 类与接口:实现关系单实现、多实现(public class 类 implements 接口1,接口2,);
- 接口与接口:可以单继承也可以多继承;
4、设计理念
抽象类是is a的共性功能,接口是like a的拓展功能;
- 某接口作为返回值类型:return 的是接口的一个实例;(体现出多态)➡️接口和抽象类都可以作为一个方法的返回值类型,接口也可以作为成员变量;
5、接口应用
数据库需要链接java需要由某某数据库的厂家来设计一个JDBC接口(一种规范)
6、接口案例
需求:声明一个person类里面有receive()接受消息方法,接受类型有微信、QQ
但随着客户新增的需求后期会接受企业微信,丁等消息类型,通过接口➕多态设计程序;
(已实现)
八、包
- 就是一个文件夹:对类进行分类管理;
package只能存在代码的第一行;
package语句在一个java文件中只能有一个;
没有package默认表示无包;
- 使用:
①以包名直接点上类名,就不用写import来导包;
②同名的类在不同的包内存在;
- 不同成员变量修饰:
1、public工程的任意位置对元素可以访问;
2、private 只能在本类访问;
3、啥也不写,默认只有在本包或者子包才能访问(不可以本子类获取)
4、protected 同上只有在本包或者子包才能访问(可以被子类访问)(其他包类不可访问)
九、内部类
1、定义
把类定义在其他类的内部,就把这个类称为内部类;
2、访问权限
内部类可以直接访问外部类的成员包括私有类;
外部类要访问内部类的成员必须创建对象;
3、使用格式
-
格式:1、定义(类A内定义一个class B)
-
创建内部类的实例:A.B b. = new A( ).new B( ); 用b.方法名调用;
-
内部类中不能有静态方法;
-
成员内部类在实际开发中基本上不会用,因为外部无法访问
-
匿名内部类:(过滤器,拦截器)创建这个接口所对应的匿名对象;
创建一个父类所对应的匿名对象;
4、内部类与接口的实际开发应用
需求:/在一个接口Login中定义一个登录1ogin()方法,然后在在定义一个用户类User,
在用户类中也定一个登录的方法1ogin(该方法的返回值是登录的接口Login),
要求通过置名内部类来完成登录的功能:
当用户名是tom123,密码是123456的时候返回登录成功!/
public interface Login {
String login();
}
package org.ali.dao.day406;
public class User{
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public Login login(){
return new Login() {
@Override
public String login() {
if (username == "tom" && password =="123456")
return "登陆成功";
else
return "登陆失败";
}
};
}
}
注意用户类中的一个内部类,是一个接口Login类型的方法,返回的也是Login类的对象,(存在疑问)这个地方把他理解为一个内部类,这个内部类重写了接口的方法。在方法内部设置了登陆的验证信息。
public class Test {
public static void main(String[] args) {
User user = new User("tom", "123456");
Login userlogin = user.login();
System.out.println(userlogin.login());
}
}