面向对象

成员变量和局部变量

成员变量局部变量
声明位置类中方法中
作用域类中方法中
默认值同数组默认值无默认值,必须赋值才能使用
生命周期随着对象存在、消失
(已初始化的成员变量先于类加载,未初始化的随类(在类后)加载)
随着所属区域的执行存在,随区域结束而释放
存储位置堆内存栈内内存的方法中
  • 调用变量名时, 成员变量和局部变量同名时,遵循就近原则;(离成员近,调的是成员;离局部近,调的是局部)

类与对象

创建对象

类名 实例名 = new 类名();

new关键字作用:在内存中,为 实例对象 申请开辟存储空间

public class Car {
	public double price;
	public String brand;
	public String color;
	
	
	public  void run() {
		System.out.println("价值"+price+"的"+color+"的"+brand+"跑了");
	}
	
	public  void stop() {
		System.out.println("价值"+price+"的"+color+"的"+brand+"停了");
	}
	
}


public static void main(String[] args) {
		Car cc=new Car();
		cc.brand="保时捷";
		cc.color="红色";
		cc.price=1240000;
		cc.stop();
	}
  • 主函数调用,中加载main函数(包含其中的内容)
  • 主函数中顺序执行:
    • car cc=new car();等号右边先执行,然后赋值给左边;
      • 等号右边:实例化,在中申请内存,新建一个car类的对象 ,包含其属性、方法等信息;(此时属性是默认值
      • 通过等号赋值给左边;对象cc在栈中的main里,接收到新建的car的信息;(此时是默认值)
    • 为cc的属性赋值,即将栈中的默认值替换为新值;cc引用指向栈中的内存地址,所以引用的属性值自然随之变化;
    • 调用cc的run方法,run方法进入栈内存,执行功能:打印属性信息拼接的字符串;(引用的是堆中cc的属性值)
  • 主函数结束,程序结束;

对象是引用类型

  • 只要2个实例指向了一个地址,对任一实例操作任意属性,其他实例的属性也会变掉~

如下图,结果是t1和t2的name都是李四;
在这里插入图片描述
如下图,最终数组指向的是2个new出来的user()的地址值

最终数组指向的是2个new出来的user()的地址值

构造函数

  • 如果不声明构造函数
    默认提供一个隐式的无参的构造函数;实例化对象时默认调用隐式无参构造函数;
  • 如果已经手动声明了有参的构造函数
    则不再提供无参构造函数,如有需要需手动再声明无参构造函数(构造函数重载)才能使用无参的;
  • 构造函数无返回类型,连void都不要写!!
  • 最先执行,优先于属性和方法的调用
  • 自动生成构造函数:alt+shift+s —— generate constructor using fields
public class Teacher {
	
	String name;
	int age;
	double height;
	int salary;
	
	public Teacher() {
		System.out.println("默认无参构造函数");
	}
	
	 public Teacher(String name,int age,double height,int salary) {
		 System.out.println("重载的有参构造函数执行");
		 this.age=age;
		 System.out.println(this.age);
		 this.name=name;
		 System.out.println(name);
		 this.height=height;
		 System.out.println(height);
		 this.salary=salary;
		 System.out.println(salary);
		 System.out.println("构造完毕");
	 }
	 
	 @Override
	public String toString() {
		// TODO Auto-generated method stub
		return "[Teacher"+":"+"name="+name+" ; age="+age+" ; height="+height+" ; salary="+salary+"]";
	}
	
}

public class Test1 {
	public static void main(String[] args) {
		System.out.println("main函数执行");//程序入口,最先执行
		Teacher t1=new Teacher("小A", 38, 183, 200);//创建对象,调用有参构造函数,构造函数进栈;t1在堆中开辟内存,并将其属性赋的值存储下来,构造函数运行完毕
		System.out.println(t1.name);
		System.out.println(t1.age);
		System.out.println(t1.height);
		
		System.out.println(t1);//自动调用重写过的toString方法,打印出来的不是地址而是固定格式的字符串
		
		Teacher t2=new Teacher();//创建第二个对象,调用无参构造函数
		System.out.println(t2);//t2的属性未赋值,按重写过得toString打印默认值
		
		System.out.println("main函数执行结束");//主函数结束
	}
}
*输出依次为:
main函数执行
重载的有参构造函数执行
38
小A
183.0
200
构造完毕
小A
38
183.0
[Teacher:name=小A ; age=38 ; height=183.0 ; salary=200]
默认无参构造函数
[Teacher:name=null ; age=0 ; height=0.0 ; salary=0]
main函数执行结束
  • 标准的实体类一般包含:属性(私有属性)、无参构造函数、重载构造函数、(get/set方法)
  • this代表被创建出来的实例对象;(而不是类)

public static void main(String[] args) {
		int i=3;
		f(i);
		System.out.println(i);//3
	}
	public static void f(int i) {
		i=4;
		System.out.println(i);//4
	}
  • i是基本数据类型,在栈中的方法体中,f方法中的i会随内存的释放而释放掉,故主方法中i仍只能取到原来的3;
public static void main(String[] args) {
		int[] arr= {1,2,3,4};
		f(arr);
		System.out.println(arr[0]);//7
		
	}
	public static void f(int[] arr) {
		arr[0]=7;
		System.out.println(arr[0]);//7
		
	}

  • arr是数组,是引用数据类型,存放在堆中,不会随方法的释放而释放掉;f方法和主函数中对arr的操作都直接指向arr在堆中的地址,对其造成影响;

  • 同一个包下的2个类互相使用,无需导包;
  • 语言包(java.lang)中的类直接用,无需导入(比如String)
  • *号是通配符,需要导入的2个类在同一个包中,直接 java.包名.*
  • 自定义的类名尽量不要与jdk已有类名重复,否则使用jdk的类时需要使用完整包路径来使用;

静态 static

  • 含义:共有的,共享数据

  • 静态内容属于整个类而不属于某个对象,只要是该类的对象,都可以使用并操作该类的静态属性,且其值都是一致的;(即通过对象操作静态内容,会直接影响全局)

  • 尽量使用类名调用静态变量,以便明示此时操作的是整个类的属性;

  • 静态变量随着类加载,随类释放(生命周期长,占内存);

  • 静态成员只能访问静态成员,不能访问非静态成员(也不能使用this)非静态成员可以访问静态成员也可以访问非静态

      非静态成员,是在创建对象并调用后才进入内存;
      静态成员在类加载时就进入内存;
      故:
      非静态成员加载的时候静态成员已经存在于内存,可以使用;
      静态成员加载的时候非静态成员还不存在,无法调用;
      this也是一样,this指代的是当前对象,也要在创建对象后才能存在;
    
  • 使用场景

    • 工具类的静态常量和方法————以便直接通过类名调用(如Math.pow() Math.PI)
    • 共享数据

封装

  • 优点:提高安全性(避免静态公有属性被随意修改)、提高复用性(方便直接通过方法名、类名、接口名调用)
  • 方式:提供私有化属性和get/set方法
public class Nurse {
	private String name;
	private String id;
	private int age;
	private String qualification;
	
	public Nurse(){
		
	}
	
	public Nurse(String name,String id,int age,String qualification){
		this.age=age;
		this.id=id;
		this.name=name;
		this.qualification=qualification;
	}

	public void setAge(int age){
		this.age=age;
	}
	public void setName(String name){
		this.name=name;
	}
	public String getName(){
		return name;
	}
	public int  getAge(){
		return age;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getQualification() {
		return qualification;
	}

	public void setQualification(String qualification) {
		this.qualification = qualification;
	}
	
	
}

一个完整的实体类需要具备:

  • 私有属性;
  • 无参构造函数;
  • 全参构造函数;
  • 私有属性的get/set方法

继承 extends

使用场景:类与类之间、接口与接口之间;

  • 父类(超类、基类 super class)已有的非私有方法和属性,子类(派生类、衍生类 subclass)可以直接使用(通过 子类实例名.父类非私有属性/方法 );

优点:提高代码的复用性;多态的前提

public class A(){
	int i =10;
	int j =30;
}

public class B extends A(){
	int i=20;
	int k=super.i;//访问父类重名成员变量的方法1
	public void f(){//访问父类重名成员变量的方法2
		System.out.println(super.i);
		return super.i;
	}
	
}

public class Test1(){
	
	System.out.println(b.j);//可以直接访问父类的非私有属性,结果30
	System.out.println(b.i);//子类和父类的成员变量重名,优先调用到的是子类的20
	
	System.out.println(super.i);//编译失败,Test1的父类是object,super指的是object,并没有i属性;
	
	System.out.println(b.k);//访问父类重名成员变量的方法1:在子类中使用super访问到当前类的父类,并接受到10;
	b.f();//访问父类重名成员变量的方法2:子类中定义方法并使用super进行访问,此处直接调方法(执行输出或者获取值都可以写在方法里);
	
}

public class TestSuper {
	int i=100;
	public void A() {
		System.out.println(i);
	}
	public void Fu() {
		System.out.println(i);
	}
}

public class TestSub extends TestSuper{
	int i =200;
	public void A() {
		System.out.println(i);
	}
	public void Zi() {
		System.out.println(i);
	}
}

public class SuperAndSub {
	public static void main(String[] args) {
		TestSub sub=new TestSub();
		sub.A();//200,重名方法,是谁调用走谁的方法,取谁的变量
		sub.Fu();//100,非重名方法,谁有这个方法走谁的方法,取谁的变量————此处是父类的方法
		sub.Zi();//200,非重名方法,谁有这个方法走谁的方法,取谁的变量————此处是子类的方法
	}
}
重写/复写/覆盖重载
名称overrideoverload
规则方法名、参数列表和修饰符都相同,方法体不同方法名相同,参数列表不同
使用情景分别在子类和父类中的2个同名方法(只发生在继承关系中)发生在同一个方法中
意义对方法功能的扩展对类的灵活性的扩展
其他子类功能更多,父类范围更广重载的方法之间没有高低优劣之分
注意事项不能为了使用某一类的方法,盲目使用继承(可以使用导入,new它的对象就好);
一个子类只能有一个父类,一个父类可以有多个子类(类只支持单继承,接口支持多继承);
不能环形继承,A继承B,B继承C,C继承A这种,NO!!!
  • 权限修饰符问题

      - 父类方法使用public/protected/default,子类重写时只要大于等于父类的范围即可;
      - public>protected>default>private;父类要是private,子类无法继承也无法重写
    
  • 重写时,先调用super.方法名();,可以方便地添加父类原有的所有功能,再在重写的代码块里写新增的功能;

@Override
	public void A() {
		super.A();
		System.out.println(i+1);
	}

继承中的构造函数

  • 子类构造函数中只要不手动调用构造函数,第一行都默认调用父类空参构造函数,super(),可以不写(隐式默认调用)
  • 如果父类属性私有,子类无法使用this关键字调用私有属性,故需要用父类属性的get/set方法给参数赋值,但这样太过麻烦。故可以在子类声明有参构造函数时调用父类的有参重载构造函数
    • 构造函数的调用super()或this()必须在第一行,所以不可能同时调用父类的有参和无参构造函数;不可能同时调用父类的构造函数和子类的构造函数(手动调用时,隐式调用父类构造函数的行为就默认取消了)
    • 本类构造函数也可以重载,在其他本类构造函数的第一行调用
public class Fu {
	private String name;
	private String color;
	private int age;
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public Fu(String name, String color, int age) {
		super();
		this.name = name;
		this.color = color;
		this.age = age;
	}
	
	public Fu() {
		super();
		// TODO Auto-generated constructor stub
	}
	
}
public class Zi extends Fu{
	int height;

	public Zi(String name, String color, int age, int height) {
		super(name, color, age);
		this.height = height;
	}
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值