1. 面向过程 & 面向对象
宏观方面需要面向对象的思想,但是微观就要使用面向过程的思想。
2. 什么是面向对象
java面向对象编程(oop)
面向对象特征:
3. 知识回顾 静态方法与非静态方法
修饰符 : static
静态方法:使用static修饰符
类可以直接调用另外一个类中的静态方法
–
非静态对象:
要 new 其他的类后才能使用其中的非静态方法。
–
在同个类中,不同的静态方法能互相调用,不同的非静态方法也能互相调用,非静态方法可以调用类中的静态方法,但是静态方法不能调用类中的非静态方法,因为二者的加载机制不同,static修饰的静态方法是和当前的类同时加载,非静态方法不是和类同时加载,静态方法相比非静态方法加载的时间要靠前一些。(听了狂神老师的课,这仅是个人理解,后面继续学习会补充这方面的知识)
非静态方法互相调用:
静态方法互相调用:
静态方法调用非静态方法:
非静态方法调用静态方法:
4. 值传递 引用传递
值传递:
//值传递
public class Demo03 {
public static void main(String[] args) {
int a = 1;
System.out.println(a);
Demo03.change(a);
System.out.println(a);
}
public static void change(int a) {
a = 10;
}
}
结果:
发现第二次输出 a 的值并没有发生改变,可见当使用值传递向 change 函数传递变量 a 时,**只是传递了 a 的值。**所以实际参数 a 的值没有改变。
–
引用传递:
//引用传递
public class Demo04 {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
Demo04.change(person);
System.out.println(person.name);
}
public static void change(Person person) {
person.name = "zqy";
}
//定义了一个Person类,有个name属性
static class Person {
String name;
}
}
运行结果:
change 函数中传递的参数是 Person 并且该函数修改了 Person 函数中的属性 name。
5. 类与对象的关系
6. 创建与初始化对象
使用 new 创建对象
public class Application {
//一个项目应该只有一个main方法
public static void main(String[] args) {
//使用 new 对抽象的类进行实例化
Student zns = new Student();
Student zqy = new Student();
zns.name="伞兵1号";
zns.age=1;
System.out.println(zns.name);
System.out.println(zns.age);
zqy.name="伞兵2号";
zqy.age=2;
System.out.println(zqy.name);
System.out.println(zqy.age);
}
}
//学生类
public class Student {
//属性,字段
String name;
int age;
//方法
public void study() {
System.out.println(this.name + "在学习!!");
}
}
7. 构造器
先写个方法,里面啥也不加:
public class Person {
}
使用另外一个启动类的main方法实例化并启动:
public class Application {
public static void main(String[] args) {
//使用 new 对抽象的类进行实例化
Person person = new Person();
}
}
发现成功运行,没有报错。
查看Person的编译文件:
和java文件对比,发现被自动添加了一个方法,这个方法就是构造方法。
–
也可以手动写显示构造器:(无参构造器)
public class Person {
public Person(){
}
}
构造器作用
1.实例化初始值(为变量进行初始化)
public class Person {
String name;
public Person() {
this.name = "zqy";
}
}
–
2.使用 new 时,本质是去自动调用类中的构造器
–
注意:如果定义了有参构造,就一定要写显示构造器(否则会报错):
写了显示构造后:
–
idea 生成构造器快捷键 alt+ins
–
构造器重载:
8. 创建对象简单内存分析
Application类:
public class Application {
public static void main(String[] args) {
Pet dog = new Pet();
dog.name = "旺财";
dog.age = 3;
System.out.println(dog.name);
System.out.println(dog.age);
Pet cat = new Pet();
}
}
Pet类:
public class Pet {
String name;
int age;
public void shout(){
System.out.println("叫了一声");
}
}
1.当使用 new 去实例化一个对象时,先经过方法内的无参构造
2.加载类,加载类中的main方法、常量
3.执行main方法,将main方法压入到栈中(main方法是最先被压入栈的,所以说,当栈中的main方法被释放后,就可以认为这个方法已经结束)
4.加载 new 的类(实例化),加载被实例化类的属性和方法(类似于加载这个类,并把它当做模板,通过这个模板生成一个对象)
例:当 new 一个dog时,第一步,在堆中分配各 new 的这个方法一块内存并分配地址,将模板存入这个内存,第二步,将dog压入栈,并指向堆中分配的内存块
5.进行赋值时,堆中的变量直接引用方法中传入的值。由于shout( ) 没有参数,所以直接调用Pet类中的方法。
6.当又new了一个cat,同样,先在栈内分配内存获取地址,并且存入模板。栈内压入cat。并指向堆内的新分配的堆内存。
总体:
9. 封装
主要思想:
–
关键字: private 与 public对应
私有化的属性不能直接通过实例化后的方法进行访问,需要使用get和set方法。
–
使用get和set
idea 自动生成get、set方法(快捷键 alt+ins):
set方法,给这个变量赋值,get方法获取到这个变量的值
//private 属性私有
public class Student {
private String name;
private int id;
//需要提供一些可以操纵这些属性的方法 get/set
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("马牛逼");
System.out.println(s1.getName());
}
}
结果:
–
通过 get set 方法能够对数据进行过滤:
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
s1.setAge(500);
System.out.println(s1.getAge());
}
}
public class Student {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 120 || age < 0) {
this.age = 3;
} else {
this.age = age;
}
}
}
–
封装的意义:
- 提高安全性,可以保护数据
- 隐藏代码的细节
- 统一接口
- 提高系统的可维护性
10. 继承
public class Person {
//人
}
public class Teacher extends Person{
}
public class Student extends Person{
}
Person是父类(基类),其他两个Student和Teacher是子类(也可以叫派生类)
被final修饰的方法不能被继承(final之后断子绝孙了)
–
查看类继承树状图:
idea快捷键 ctrl + H
注意:所有的类都默认继承了Object类
11. Super详解
与this关键字是一对,this代表当前的类,super代表父类
–
访问父类变量:
代码:
public class Person{
protected String name = "zqy1";
}
public class Student extends Person {
private String name = "zqy2";
public void say(String name) {
System.out.println(name);
System.out.println(this.name);//访问自身属性
System.out.println(super.name);//访问父类属性
}
}
public class Application {
public static void main(String[] args) {
Student student1 = new Student();
student1.say("zqy3");
}
}
–
访问父类方法:
代码:
public class Person{
public void print(){
System.out.println("我是父类");
}
}
public class Student extends Person {
public void print() {
System.out.println("我是子类");
}
public void test() {
print();
this.print();
super.print();
}
}
public class Application {
public static void main(String[] args) {
Student student1 = new Student();
student1.test();
}
}
–
注意:私有属性(private)无法被继承。
–
子类默认调用了父类的无参构造
例:
super( ); 默认隐性使用,如果要显性使用,就必须要在子类的第一行。
同样当使用this( );调用本类的构造参数时,也要在第一行。
–
啊这。。。。遇见问题了:这该如何是好
太菜了没见过。。。。。。
–
当使用super( ) ;调用有参构造时,要传入参数:
写完有参就没有无参了
–
12. 方法重写
重写是方法的重写,与属性无关。
只有非静态方法才能重写。
public class B {
public void test(){
System.out.println("B");
}
}
public class A extends B{
@Override
public void test() {
//在这里重写父类的 test()方法
System.out.println("我很牛");
}
}
执行结果:
当使用static静态方法时:
小结:当使用static修饰方法时,方法调用只与new方法左边的有关,例如上图,分别使用B和A去new一个A方法,并调用其中的test()方法,结果是分别调用了属于左边类的方法(A调用了A中的test,B调用了B中的test)并没有进行重写操作。当不使用static修饰后,才会进行方法重写。(要进行重写的方法的修饰符必须为public)
–
13. 什么是多态
例:
public class Student extends Person {
//子类
}
public class Person{
//父类
}
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确认的(Student对应Student,Person对应Person)
Student s1 = new Student();
Person p1 = new Person();
//可以指向的引用对象类型就不确定了:父类引用指向子类
Student s2 = new Student();
Person s3 = new Student();
Object p2 = new Person();
}
}
同时调用一个方法,如果子类没有重写,就调用父类中该方法,如果子类进行重写,就调用子类重写后的方法。
–
例2:
代码:
public class Person {
public void run() {
System.out.println("父");
}
}
public class Student extends Person {
@Override
public void run() {
System.out.println("子");
}
public void eat() {
System.out.println("吃");
}
}
public class Application {
public static void main(String[] args) {
//Student可以调用的方法:自己独有的或者继承的方法
Student s2 = new Student();
//Person 父类型:可以指向子类,但不能调用子类独有的方法
Person s3 = new Student();
Object p2 = new Person();
//对象能执行哪些方法,主要看等于号左边的类型,和右边的关系不大
s2.eat();
//父类型不能直接调用子类特有的方法,如果要调用,要进行强制类型转换
s3.eat();
((Student) s3).eat();
//子类重写了父类的方法,所以当父类调用这个被重写的方法是直接调用自子类重写后的方法
s2.run();
s3.run();
}
}
运行结果:
–
小结:(static,final,private修饰的方法不能被重写)
再次强调:只有方法有多态,属性没有多态。
14. instanceof关键字
用来判断两个类之间是否存在父子关系(继承关系)
例:
public class Student extends Person {
//子类
}
public class Teacher extends Person{
//子类
}
public class Person{
//父类
}
public class Application {
public static void main(String[] args) {
/*
继承关系
Object > String
Object > Person > Teacher
Object > Person > Student
*/
Object o1 = new Student();
System.out.println(o1 instanceof Student);
System.out.println(o1 instanceof Person);
System.out.println(o1 instanceof Object);
System.out.println(o1 instanceof Teacher);
System.out.println(o1 instanceof String);
Person p1= new Student();
System.out.println(p1 instanceof Student);
System.out.println(p1 instanceof Teacher);
System.out.println(p1 instanceof Object);
// System.out.println(p1 instanceof String);//编译报错
}
}
总结公式:
X instanceof Y,当X和Y之间存在继承关系则该关系式的值为true。
–
类型转换
与变量类型转换原理相同,父类向子类转换(高 --> 低)需要强制类型转换,可能会导致子类的一些方法丢失,反之则不需要。
public class Student extends Person {
//子类
public void go(){
System.out.println("go");
}
}
public class Application {
public static void main(String[] args) {
Person s1 = new Student();
//s1类型为Person,是Student的父类,所以,当s1要调用子类Student中的go方法时,要进行强制类型转换
((Student) s1).go();
//子类转化为父类,低-->高 直接转化
Student s2 = new Student();
s2.go();
Person p1 = s2;
}
}
–
小结:
15.static关键字
1. 可以使用类名直接访问static修饰的变量(静态变量)
public class Student {
private static int age;//静态变量
private double money;//非静态变量
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(Student.age);
System.out.println(s1.age);
System.out.println(s1.money);
}
}
不能通过类名访问非静态变量
同样,静态方法也可以这么调用:
public class Student {
public void run() {
//非静态方法
}
public static void go() {
//静态方法
}
public static void main(String[] args) {
new Student().run();
Student.go();
go();//还可以直接调(因为是在当前的类中)
}
}
静态方法能调用静态方法,非静态方法可以调用静态方法和非静态方法
–
2. 代码块
public class Person {
{
//匿名代码块
}
static {
//静态代码块
//和类同时加载,只生效一次
}
}
–
代码块、静态代码块、构造方法三者的加载顺序:
public class Person {
//第二执行
{
//匿名代码块
System.out.println("匿名代码块");
}
//最先执行
static {
//静态代码块
//和类同时加载,只生效一次
System.out.println("静态代码块");
}
//最后执行
public Person() {
System.out.println("构造方法");
}
public static void main(String[] args) {
new Person();
}
}
再次new一个Person:
静态代码块只执行了一次
静态代码块的作用
赋初始值
3.静态导入包
例:
当我们要使用java封装好的方法时(以随机数生成为例)
需要输入 Math.random();非常的麻烦,
我们可以通过import直接导入Math包的random:
//静态导入
import static java.lang.Math.random;
public class Test {
public static void main(String[] args) {
System.out.println(random());
}
}
但是这种方法不怎么用…
16. 抽象类
写一个抽象类:
//abstract 修饰抽象类
public abstract class Action {
//abstract 抽象方法,只有方法名,没有方法的实现
public abstract void doSomthing();
}
子类如果继承抽象类,就必须重写里面的方法:
//抽象类的所有方法必须要由子类实现(重写)
public class A extends Action{
@Override
public void doSomthing() {
}
}
如果继承抽象方法的子类也是一个抽象方法,就不需要重写里面的方法,就会让一个不是抽象方法的子类(或者子类的子类)去重写
–
小结:
抽象类提高开发效率,将一些常用的变量进行抽象类封装
–
再看看抽象类有没有构造方法:
这个还真有。
17. 接口
//通过interface关键字定义接口
public interface UserServer {
//接口中的所有定义都是抽象的 默认已经有public abstract了,所以写上会变成灰色
public abstract void run();
//也可以直接省略public abstract
void run2();
}
接口只是起到定义方法的作用,要实现方法还需要一个实现类
定义一个实现类,命名规范,一般要在实现类的名后添加一个Impl:
通过implements关键字链接定义好的接口,并重写接口中定义的方法
public interface UserServer {
void insert();
void delete();
void update();
void query();
}
public class UserServerImpl implements UserServer{
@Override
public void insert() {
}
@Override
public void delete() {
}
@Override
public void update() {
}
@Override
public void query() {
}
}
一个类可以链接多个接口:接口之间用逗号分隔。
接口从侧面实现了extends无法实现的多继承。
如果在接口中定义常量:
public interface UserServer {
//默认接口中定义的是常量public static final
public static final int age=99;
//也可以省略public static final 也是默认常量
int ages=100;
void insert();
void delete();
void update();
void query();
}
一般不用
–
18. 内部类
1. 成员内部类
例:
public class Outer {
private int age;
public void out(){
System.out.println("这是外部类方法");
}
public class Inner{
public void in(){
System.out.println("这是内部方法");
}
}
}
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
outer.out();
//通过这个外部类来实现内部类
Outer.Inner inner = outer.new Inner();
inner.in();
}
}
可以通过内部类来获取到外部类的私有属性:
–
2. 静态内部类
通过static修饰的内部类
–
3. 局部内部类
public class Outer {
//局部内部类
public void methon() {
class A {
public void in() {
}
}
}
}
扩展:
public class Outer {
}
//一个java类中可以有多个class类,但是只能有一个public修饰的class类
class A{
public static void main(String[] args) {
}
}
–
4. 匿名内部类
public class Outer {
public static void main(String[] args) {
//没有名字的初始化类和接口,不需要将实例保存在变量中
new A().eat();
//会返回一个UserServer的对象
UserServer userServer = new UserServer() {
@Override
public void run() {
}
};
}
}
class A {
public void eat() {
System.out.println("吃");
}
}
interface UserServer {
void run();
}
完
转载:https://blog.csdn.net/zhouqiyuan1233/article/details/115176937