形式参数分别为基本类型和引用类型的不同情况?
方法的形式参数如果是基本类型,实际参数该如何传递?
只需要在括号内输入基本类型数值即可
方法的形式参数如果是类(引用类型),实际参数该如何传递?
如果方法的形式参数是类,实际参数传递,需要传递的是当前类的具体类对象
匿名对象格式及好处:
格式 : new 类名();
- 匿名对象可以作为参数传递,
- 匿名对象可以节省内存空间,因为没有栈内存空间,不需要开辟,直接开辟堆内存空间
- 匿名对象一般适用一次即可,适用完毕,直接被jvm的GC(垃圾回收器)回收
代码体现:
package com.qf.noname_04;
/**
* Java中有一个概念:匿名对象: 毋庸置疑,没有名字对象;
* 之前: 类名 对象名 = new 类名() ; 对象名
* Student s = new Student() ; 里面的对象名是s
* 对象名.访问成员方法();
*
* 匿名对象:
* 格式:new 类名() ;
*
* 匿名对象调用方法
* new 类名().成员方法名() ;
* 好处:节省内存空间,new 类名() ;
* 匿名对象可以作为参数传递
* 创建完毕之后,没有栈内存指向,所以使用完毕,立即被GC(垃圾回收器回收)
* 一般情况:匿名对象使用一次即可,这样不需要过多的去开辟堆内存空间,直接被回收;
*
*
*/
//学生类
class Student{
public void study(){
System.out.println("Good Good Study,Day Day Up!");
}
}
//定义StudentDemo类
class StudentDemo{
public void method(Student s){//形式参数是一个Student类型,引用类型
s.study();//调用该方法,应该使用实际参数对象名在访问
}
}
//测试类
public class NoNameDemo {
public static void main(String[] args) {
//要访问StudentDemo类中method方法
//创建StudentDemo类对象|
StudentDemo sd = new StudentDemo() ;
//创建学生对象
Student s = new Student() ;
sd.method(s); //方法里面:形式参数 创建学生了学生对象
System.out.println("---------------------------------");
//使用匿名对象new 类名()
//new 类名().成员方法名() ; //调用自己方法
sd.method(new Student());
System.out.println("---------------------------------");
//再次优化:
//链式编程(自己去玩,开发中很少)
new StudentDemo().method(new Student());
}
}
this关键字的概念以及目的
this:代表当前类对象的地址值引用
Student s=new Student(); s--->空间地址值引用
this的出现: 为了防止局部变量隐藏了成员变量
this的用法:
this.变量名; 变量名:访问本类的成员变量名
this.方法名(); 访问的本类的成员方法
this(); 访问本类的无参构造方法
this(***); 访问本类有参构造方法
构造方法的特点和注意事项
构造方法的特点:
- 方法名和类名相同
- 没有具体返回值
- 连void都没有
构造方法的目的:就是为给类的成员初始化
Phone p=new Phone(); --->无参构造方法
- 栈内存开辟空间
- 堆内存申请空间
- 进行系统默认初始化,为成员变量
- setXXX("xxx") --->有参构造方法,显示初始化
构造方法的注意事项:
- 当在书写一个标准类的时候,没有给出任何构造方法.系统会默认提供无参构造方法
- 如果提供了一个类的有参构造方法,系统就不会构造方法,所以,建议永远给出无参构造方法;
- 构造方法是可以重载的
代码体现:
package com.qf.test;
public class PersonTest {
public static void main(String[] args) {
Person p=new Person("张三",33,173);
Person p2=new Person("李四",44,174);
p.sayHello();
System.out.println("年龄:"+p.getAge()+",身高:"+p.getWeight());
p2.sayHello();
System.out.println("年龄:"+p2.getAge()+",身高:"+p2.getWeight());
}
}
class Person{
private String name;
private int age;
private double weight;
public Person() {
}
public Person(String name, int age, double weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public void sayHello(){
System.out.println("hello my name is"+name);
}
}
一个类成员的组成以及一个类的标准写法
一个类的组成:
- 成员方法
- 成员变量
- 构造方法
一个标准类的写法:
- 成员变量私有化
- 无参永远给出,有参构造根据题意要求(没有明确,全部提供)
- 成员方法,根据题意要求(没有明确是否带参,是否有返回值,直接输出语句)
继承
概述: 将多个类的共性内容抽取出来,放在一个独立的类中,让这个独立的类和其他类产生一种关系--->继承 关键字extends
继承的特点:
- 在java语言中,类和类的关系是一种继承关系,这个继承只能支持单继承,不支持多继承但是支持多级继承
继承的好处:
- 可以提高代码的复用性
- 可以提高代码的维护性,后期便于维护,针对子类和父类进行维护(字符关系明确)
- 类与类产生继承关系,是多态的前提条件
注意事项:
- 子类继承父类,对于非私有的成员,直接可以继承过来,但是如果是私有成员,它可以通过公共的方法访问
- 被私有修饰的东西(成员变量/成员方法),只能在当前类访问
在Java中有一个开发原则 "低耦合,高内聚"(以后所有的Java设计模式都需要遵循这一个原则)
耦合性:开发中是永远避免不了,可以降低(耦合:类和类的关系)
内聚性:指的是某个类完成某个功能的一种能力; 尽量不要产生继承关系来完成一个功 能,一个类能完成一个类完成;
低耦合:降低耦合性,减少类和类的关系;
代码体现:
package com.qf.test;
public class PersonTest {
public static void main(String[] args) {
NorthPerson np=new NorthPerson("张三",24,"工人");
System.out.println(np.getName()+"---"+np.getAge()+"---"+np.getProfession());
np.eat();
np.exam();
SouthPerson sp=new SouthPerson("李四",25,"老师");
System.out.println(sp.getName()+"---"+sp.getAge()+"---"+sp.getProfession());
sp.eat();
sp.business();
}
}
class Person{
private String name;
private int age;
private String profession;
public Person() {
}
public Person(String name, int age, String profession) {
this.name = name;
this.age = age;
this.profession = profession;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getProfession() {
return profession;
}
public void setProfession(String profession) {
this.profession = profession;
}
public void eat(){
System.out.println(name+"喜欢吃");
}
}
class SouthPerson extends Person{
public SouthPerson() {
}
public SouthPerson(String name, int age, String profession) {
super(name, age, profession);
}
@Override
public void eat() {
super.eat();
System.out.println(super.getName()+"喜欢吃米饭");
}
public void business(){
System.out.println(super.getName()+"喜欢经商");
}
}
class NorthPerson extends Person{
public NorthPerson() {
}
public NorthPerson(String name, int age, String profession) {
super(name, age, profession);
}
@Override
public void eat() {
super.eat();
System.out.println(super.getName()+"喜欢吃面");
}
public void exam(){
System.out.println(super.getName()+"喜欢考公");
}
}
static关键字的特点:
- 被静态修饰的随着类的加载而加载,优先于对象的存在
- 不能和this共存
- 本身含义就是共享,共用,可以多个对象共享共用
- 被静态修饰的成员变量或者成员方法(静态变量,静态方法)访问的方式:
类名.变量名
类名.方法名
静态的使用场景以及适用范围:
静态方法中只能访问静态方法
静态方法只能调用静态方法
非静态方法皆可以访问静态的东西也可以访问非静态的东西
class Demo{
int num = 10 ;//非静态的
static int num2 = 20 ;//静态的
//非静态的成员方法
public void show(){ //非静态既可以调用静态/非静态方法
System.out.println("show Demo");
method(); //调用静态方法
System.out.println(num2) ;
System.out.println(num);
}
//静态的成员方法
public static void method(){ //静态只能访问静态
System.out.println("method Demo");
// show() ;
System.out.println(num2);
// System.out.println(num);//num是静态的
}
}
//测试类
public class StaticDemo {
public static void main(String[] args) {
//访问num和num2 ---都可以使用对象来访问
Demo d = new Demo() ;
System.out.println(d.num) ;//10
// System.out.println(d.num2) ;//20 //不推荐 对象名.变量名 num2静态的---属于类成员
System.out.println(Demo.num2);//类名直接访问;
System.out.println("-------------------------------------") ;
//调用show()
d.show();
//d.method() ; //对象名.静态方法名() 可以的,idea不会提示 ;不推荐,静态方法随着类加载而加载
//类名直接访问;
Demo.method() ;
System.out.println("---------------------");
int result = add(10, 20); //main方法是静态的,main中调用其他方法必须静态,否则报错;
System.out.println(result);
}
//自定义了一个方法
public static int add(int a,int b){
return a+b ;
}
}
继承关系中,构造方法的访问
子类继承父类,子类的所有构造方法都默认访问父类的无参构造方法
子类继承父类,会用到父类的数据,需要让父类先进行初始化(一个类的初始化,肯定需要执行构造方法的)
关键字super:
super:
代表父类的空间标识(代表父类的地址值引用)
this和super的区别:
this.变量名 访问本类的成员变量
super.变量名 访问父类的成员变量
this.方法名() 访问本类的成员方法
super.方法名() 访问父类的成员方法
this() 访问本类无参构造方法
super() 访问父类的无参构造方法
this(xxx) 访问本类的有参构造方法
super(xxx) 访问父类的有参构造方法
注意: 子类继承父类,一定要先执行父类构造方法,初始化完毕之后,然后才能执行子类的构造方法---->分层初始化
实际开发中,常用到:
子类的无参构造方法----->默认父类无参构造方法
子类的有参构造方法----->直接访问父类的有参构造方法
静态代码块,构造代码块,构造方法的优先级
每次执行构造方法之前,如果存在构造代码块,先执行构造代码块
静态代码块,随着类的加载而加载,类加载一次,静态代码块执行一次
静态代码块>构造代码块>构造方法
继承中的方法重写
子类继承父类,成员变量的访问问题:
情况1: 子类和父类的中成员变量名称不一致,访问比较简单,分别访问即可!
情况2:子类和父类的成员变量名称一致: 如何访问呢?
- 先在子类的局部位置找,有没有这个变量,有就使用;
- 如果没有,在子类成员位置中找,有没有这个变量,有就使用;
- 如果子类的成员位置也没有,然后会在父类的成员位置找,有没有这个变量,有就使用;
- 如果父类的成员位置都没有,报错(前提:这个父类没有它的父类了),说明整个子父类中 都没有变量;
- 遵循"就近原则"
代码体现:
class Zi extends Fu{
//成员变量名称
//int num2 = 30 ;
//int num = 50 ;
//子类的成员方法
/* public void show(){
// System.out.println(num) ;//访问父类的成员变量
// System.out.println(num2) ;//访问本类的成员变量
}*/
//method方法
public void method(){
//局部变量
//int num = 100 ;
System.out.println(num);
}
}
//测试类
public class ExtendsDemo {
public static void main(String[] args) {
//创建子类对象
Zi z = new Zi() ;
//z.show() ;
z.method();
}
}
子类继承父类,成员方法的访问
情况1:子类和父类成员方法名称不一致,比较简单,分别调用即可
情况2:子类和父类的成员方法名称一致:权限修饰符,返回值类型,参数列表都一样
方法重写:
Override---->子类在父类的基础上,将父类的方法覆盖了,使用自己的功能
方法重写override和方法重载overload有什么区别?
方法重写:出现在继承中,描述的子类继承父类的时候,可能沿用父亲的功能,而且使用自己的功能,将父类的功能进行覆盖(复写/重写);为了让子类具体体现出来的功能信息
方法重载:定义方法的时候,方法名相同,参数列表不同,与返回值无关;目的为保证这个方法它的扩展性问题,同一个方法,可以不同类的参数;
代码体现:
//以前的手机
class Phone{
public void callPhone(){
System.out.println("手机可以电话了....");
}
}
//新手机
class NewPhone extends Phone{
//子类将父类的方法覆盖了
public void callPhone(){
super.callPhone() ; //将父类的方法沿用了
System.out.println("听音乐") ;
System.out.println("玩游戏....");
}
}
final关键字
final: 最终的,无法修改的,状态修饰符,被final修饰的成员方法不能被重写,保证父类的安全性
final可以修饰类,该类不能被继承
final可以修饰变量,此时这个变量是一个常量
final修饰成员方法,此时这个方法不能被子类重写,目的为了保证方法中某些数据的安全性
注意事项:
final修饰的变量只能被赋值一次,不能多次
final修饰基本类型,基本数据类型的值不能在改变
final修饰引用数据类型,引用数据类型:对象的地址值不能在改变
多态
宏观角度:一个事物在不同时刻体现的不同形态
微观角度:具体对象在内存中的变化(对象在不同时刻的类型)
多态的前提条件:
- 必须有继承关系
- 必须存在方法重写,子类部分功能将父类的功能进行覆盖,子类使用自己的功能体现
- 必须存在父类引用指向子类对象
例如:
class Fu{}
class Zi extends Fu{}
向上转型:使用父类的东西
父类名 对象名 =new 子类名();
Fu fu=new Zi(); --->父类引用指向子类对象
如果子类中由特有方法,使用强制类型转化
Zi zi =(Zi)fu;
多态的成员访问特点:
父类名 对象名 =new 子类名();
成员变量:
编译看左,运行看左 ;
成员方法 :非静态
编译看左,运行看后, 因为子类重写了父类的功能!
静态方法:即使子类出现了和父类一模一样静态方法,不算重写,因为静态方法都是自己类相关的,类成员!
编译看左,运行看左;构造方法:多态的前提条件,有继承关系,跟继承一样,分层初始化
先执行父类的构造方法,然后再是子类的构造方法
多态的弊端
1.有继承关系了 2.有重写了 3.有父类引用指向子类对象 Fu f = new Zi() ;
无法调用子类的特有功能!
如何解决呢?
方案1:创建自己的子类对象
子类名 对象名 = new 子类名() ;
方案1不好地方:本身Fu fu = new Zi() ;已经开辟堆内存空间了,
Zi zi = new Zi();又要在堆内存开辟空间,消耗内存空间比较大 ;
方案2: 多态的第三个前提条件:父类引用指向子类对象
能不能将 将父类的引用 强制为子类的引用呢?
可以:
向下转型
前提必须向上转型Fu fu = new Zi() ;
Zi z = (Zi)fu ; //强转的语法
这样的好处:节省内存空间
代码体现:
package com.qf.test;
/*南方人和北方人都有姓名,年龄以及性别,职业,都有"吃饭"的功能,但是南方人经常吃米饭,北方人经常吃面条,
南方人主要还去经商,北方人主要考学,请使用继承的实现 使用代码实现(测试的时候使用多态进行测试)*/
public class PersonTest {
public static void main(String[] args) {
Person p=new NorthPerson("张三",21,"男","程序员");
NorthPerson np=(NorthPerson)(p);
np.eat();
np.exam();
Person p1=new SouthPerson("李四",22,"男","商人");
SouthPerson sp=(SouthPerson) (p1);
sp.eat();
sp.jingshang();
}
}
class Person{
private String name;
private int age;
private String sex;
private String zhiye;
public Person() {
}
public Person(String name, int age, String sex, String zhiye) {
this.name = name;
this.age = age;
this.sex = sex;
this.zhiye = zhiye;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getZhiye() {
return zhiye;
}
public void setZhiye(String zhiye) {
this.zhiye = zhiye;
}
public void eat(){
System.out.println(name+"吃...");
}
}
class NorthPerson extends Person{
public NorthPerson() {
}
public NorthPerson(String name, int age, String sex, String zhiye) {
super(name, age, sex, zhiye);
}
@Override
public void eat() {
System.out.println(super.getName()+"吃面条");
}
public void exam(){
System.out.println(super.getName()+"喜欢考学");
}
}
class SouthPerson extends Person{
public SouthPerson() {
}
public SouthPerson(String name, int age, String sex, String zhiye) {
super(name, age, sex, zhiye);
}
@Override
public void eat() {
System.out.println(super.getName()+"喜欢吃米饭");
}
public void jingshang(){
System.out.println(super.getName()+"喜欢经商");
}
}
多态的好处:
- 提高代码的复用性,由继承保证
- 提高代码的扩展性,由多态保证:父类引用指向子类对象
代码体现:
//动物类
class Animal{
public void eat(){
System.out.println("动物都需要吃饭");
}
public void sleep(){
System.out.println("动物都需要休息");
}
}
//猫类
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼"); //重写了
}
@Override
public void sleep() {
System.out.println("猫躺着休息"); //重写了
}
}
//狗类
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
@Override
public void sleep() {
System.out.println("狗侧着休息");
}
}
class Pig extends Animal{
@Override
public void eat() {
System.out.println("猪吃白菜");
}
@Override
public void sleep() {
System.out.println("猪趴着休息");
}
}
//这个类:封装使用猫或者狗的功能
class AnimalTool{
//将构造私有化: 外界不能创建当期类对象--->只能提供外静态方法
private AnimalTool(){}
/* public static void userCat(Cat c){ //形式参数
c.eat();
c.sleep();
}
public static void userDog(Dog d){//形式参数
d.eat();
d.sleep();
}
public static void userPig(Pig p){//形式参数
p.eat();
p.sleep();
}*/
//多态的应用场景: 父类引用可以指向子类对象
//方法的形式参数直接传递父类型 //相当于这个方法形式参数 --->Animal a = new Cat();
//方法的形式参数直接传递父类型 //相当于这个方法形式参数 --->Animal a = new Dog();
//方法的形式参数直接传递父类型 //相当于这个方法形式参数 --->Animal a = new Pig();
public static void userAnimal(Animal a) { //形式参数 父类类型, 父类名 对象名 = new 子类名();
a.eat();
a.sleep();
}
}
//测试类
public class DuoTaiDemo {
public static void main(String[] args) {
//创建猫类对象
//没有使用多态之前
Cat cat = new Cat() ;
cat.eat();
cat.sleep();
//养了一只狗,创建狗对象
Dog dog = new Dog() ;
dog.eat();
dog.sleep();
System.out.println("---------------------------------") ;
//猫 吃/睡 狗 吃/睡
//优化:方法的形式参数可以是引用类型 ,调用方法的时候,实际参数需要传递当前类对象
// 定义静态的两个功能:userCat(Cat c) userDog(Dog d)
// Cat c = new Cat() ;//创建猫对象
//userCat(c); //实际参数:空间地址值
// Dog d = new Dog() ;//创建狗对象
//userDog(d); //实际参数:空间地址值
//匿名对象可以作为参数传递
// userCat(new Cat());
//userDog(new Dog());
System.out.println("-------------------------------");
//如果子类型越来越多 pig,monkey....具体动物很多,会造成代码量大,单独提供userXXX功能(XXX类型)
//学习了面向对象,应该将这些功能封装到一个类中,通过对象来访问或者静态方法,类名来访问
//定义一个类AnimalTool
/* Cat c = new Cat() ;
AnimalTool.userCat(c);
// AnimalTool.userCat(new Cat());
Dog d = new Dog() ;
AnimalTool.userDog(d); //实际参数
AnimalTool.userPig(new Pig());*/
//测试
//多态的应用
Animal a = new Cat() ;
AnimalTool.userAnimal(a);
// AnimalTool.userAnimal(new Cat());
a = new Dog() ;
AnimalTool.userAnimal(a);
a = new Pig() ;
AnimalTool.userAnimal(a);
}
//使用猫的功能
/* public static void userCat(Cat c){ //形式参数
c.eat();
c.sleep();
}
public static void userDog(Dog d){//形式参数
d.eat();
d.sleep();
}
public static void userPig(Pig p){//形式参数
p.eat();
p.sleep();
}*/
}
抽象类 abstract
在一个类中,如果有抽象方法,这个类必须是抽象类
抽象类中可以是抽象方法,可以是具体方法
抽象方法的格式:
和写方法的格式引用,加入一个关键字abstract,而且没有方法体{}
public abstract 返回值类型 方法名(空参/带参)
抽象类的特点:
- 不能实例化(不能创建对象)
- 必须强制子类完成方法重写
抽象类的子类:
如果子类是一个抽象类,没有意义(抽象类new不了)(前提是这个子类没有它的子类)
研究的抽象类的子类一定会有一个具体类,这个时候通过具体类才能创建对象
抽象的父类名 对象名=new 具体的子类名(); //抽象类多态
抽象类的成员特点:
成员变量:抽象类的成员变量既可以是变量,也可以是自定义常量被final修饰
成员方法:抽象类中既可以有抽象方法,也可以有非抽象方法
构造方法:既可以定义无参构造方法,也可以是有参构造方法
存在抽象类多态,有继承关系,初始化的时候,构造方法----分层初始化---->先父类初始化,子类初始化
abstract 和那些关键字冲突
和private关键字冲突:因为被private私有的成员方法只能在本类访问,而abstract修饰的成员方法
必须强制子类重写,已经超出来的当前类的范围
和final也冲突,被final修的成员方法,不能被重写;而抽象方法强制子类必须重写;
和static也冲突,abstract修饰的方法必须被子类重写,而static修饰的方法,算不上抽象,直接跟类相关的;
abstract关键字 应用范围: 定义在类上---抽象类
定义在方法上----抽象方法
public abstract 返回值类型 方法名(空参/带参...) ;
abstract 返回值类型 方法/名(空参带参...) ;
接口
接口特点
接口用关键字 interface 表示格式: interface 接口名 {}类实现接口用 implements 表示格式: class 类名 implements 接口名 {}接口不能实例化那么,接口如何实例化呢 ?按照多态的方式,由具体的子类实例化。其实这也是多态的一种,接口多态。接口的子类要么是抽象类要么重写接口中的所有抽象方法
接口成员的特点:
成员变量:只能是常量默认修饰符 public static fifinal---->可以省略构造方法:没有,因为接口主要是扩展功能的,而没有具体存在成员方法:只能是抽象方法默认修饰符 public abstract
类与类,类与接口,接口与接口的关系
类与类继承关系,只能单继承,但是可以多层继承类与接口实现关系,可以单实现,也可以多实现。还可以在继承一个类的同时实现多个接口接口与接口继承关系,可以单继承,也可以多继承
抽象类和接口的区别:
成员区别抽象类 变量, 常量;有抽象方法;非抽象方法,构造方法 ,接口 常量;抽象方法(没有构造方法)关系区别类与类 继承,单继承类与接口 实现,单实现,多实现接口与接口 继承,单继承,多继承设计理念区别抽象类 被继承体现的是: ”is a” 的关系。共性功能接口 被实现体现的是: ”like a” 的关系。扩展功能
附加:
成员变量和静态变量的区别?
位置不同:
成员变量 堆内存中
静态变量 方法区的静态区
初始化不同:
成员变量 和对象有关,将对象创建出来
静态变量 静态变量与类相关,称为类成员,初始化远远早于对象的创建
访问方式不同:
成员变量 类中方法外,随着对象的创建完毕,等待垃圾回收器回收而消失
静态变量 随着类的加载而加载,类加载一次静态的东西,具有共享性