笔记之java基础--08

1、random类,获取一个1-100之间的随机数。
A:(int)(Math.random()*100)+1;
B:Random r = new Random();
  int num = r.nextInt(100)+1;
构造方法:
Random();使用默认的种子,当前时间的毫秒值,每次产生的随机数都是变化的。
Random(long seed);如果给定了种子,每次都是按照种子做出初始值产生的随机数如果种子固定,则值是固定的。
成员方法:
int nextInt():int范围内的一个数据

int nextInt(int n):在0到n范围内的一个数据,包括0不包括n.

2、继承的由来:

class Student

{

private String name;

private int age;

public Student(){}    

public void setName(String name)

{

this.name = name;

}

public void setAge(int age)

{

this.age = age;

}

public String getName()

{

return name;

}

public int getAge()

{

return age;

class Teacher

{

private String name;

private int age; 

public Teacher(){}   

public void setName(String name)

{

this.name = name;

}

public void setAge(int age)

{

this.age = age;

}

public String getName()

{

return name;

}

public int getAge()

{

return age;

}

}

/*

这个时候我们发现一个问题,假如将来有很多这样类似的类,那么,代码的重复度是很高的。

这样我们的有效代码其实不是很多。我们就这样思考:加入我们能够把这些类中的相同的内容提取出来定义在一个类中,

然后,让其他的类和这个定义的类产生一个关系,有了这个关系,他们就都具备了这个类定义的功能。

很对这种情况,java提供了继承:  提高代码的复用性。如果采用继承,怎么体现代码呢?

继承的格式:

class A extence B

{

}

表示类A继承了类B

class Person

{

private String name;

private int age;

public Person(){}   

public void setName(String name)

{

this.name = name;

}

public void setAge(int age)

{

this.age = age;

}

public String getName()

{

return name;

}

public int getAge()

{

return age;

}

class Student extence Person

{

}

class Teacher extence Person

{

}

叫法:

person叫做父类,基类,超类

Student,叫做子类,派生类

注意:

     子类可以直接访问父类中的非私有的属性和行为。

*/

2、通过继承我们可以使用父类中的非私有成员(成员变量和成员方法)
 
class Person
{
private void math()
{

System.out.println("蓝色大海的传说");
}
public void show()
{
math();
System.out.println("我爱林青霞");
}
}
class Student extends Person
{
public void function()
{
//math();报错,因为math是私有,只能在父类中被访问,子类不能继承父类的私有方法
show();
}
}
class ExtendsDemo 
{
public static void main(String[] args) 
{
Person p = new Person();
p.show();
//p.math();报错,因为math是私有方法,只能在本类中调用

Student t = new Student();
t.show();
//t.math();报错,因为math是私有方法,只能在本类中调用
t.function();
}

}

3、继承的好处:
A:提高了代码的复用性。
B:让类与类中产生一个关系,是多态的前提。
特点:
A:java只支持单继承不支持多继承。
B:java支持多层(重)继承(继承体系)。
  子女可以继承父亲和爷爷的,coder继承了student,student继承了person所以相当于coder继承了person.
什么时候把类的关系定义为继承。
A:由于继承体现了一种关系, is a的关系,xxx is yyy的一种
以后定义多个类时(A,B):
如果A is a B的一种,或者B is a A,
那么他们之间存在继承关系,前者A是子类,后者B是子类。

B:发现有相同方法是就采用继承,但是不要为了获取其他类中的某个功能而采用继承。

  主要还是从他们之间的关系考虑。

4、super:

1)类的组成:
成员变量
成员方法
构造方法
研究父子类的成员变量关系?
通过子类访问一个成员的时候:
A:首先在局部范围内找,有就是用。
B:继续在成员位置找,有就使用。
C:最后在父类中找,有就使用。
D:还没有就报错。
现在要在子类中,输出局部范围的值,输出成员变量的值,输出父类成员变量的值。
A:局部范围的值,直接输出变量名即可
B:成员范围输出this.变量名即可。
C:父亲的成员范围,用super关键字
  this代表的是本类的成员变量,supre代表的是父类中的成员变量。
2)super关键字:
A:和this的用法很像
B:this代表本类对象的引用,super代表父亲空间的内存表示(可以理解为父亲的对象引用)。
C:当子父类出现同名的时候可以用super进行区分。
D:子类要调用父类的构造函数,可以用super语句。
this和super的使用:
成员变量:
this.变量-----当前类的变量
super.变量----父类的变量

构造方法:
this(参数)----调用本类的其他构造方法
super(参数)-----调用父类的构造方法

成员方法:
this.方法名()----本类的方法
super.方法名()---父类的方法

5、子父类的成员方法调用

       1)方法的覆盖:

                子类中出现和父类一样的方法时,会出现覆盖操作,也称为重写。

                即通过子类找方法时,现在子类中找,如果有则用子类中的方法,如果没有则用父类的方法。

        面试题:方法重写和方法重载的区别?

                方法重写是指:子父类中出现方法相同的情况,被称为方法重写。返回值,方法名,参数一样。

                方法重载指的是:在同一个类中,方法名相同,参数列表不同,跟返回值没有关系。

       2)子父类方法重写的注意问题:
A:父类中的私有方法不可以被重写。
B:覆盖时,子类方法访问权限一定大于等于父类方法权限。
C:静态只能覆盖静态。
因为静态随着类的加载而加载,而非静态随着对象的加载而加载。

D:在子类覆盖方法中,继续使用被覆盖的方法,可以通过super.函数名获取。

        代码分析:

class Phone
{
private void show()
{
System.out.println("private phone");
}
public void method()
{
System.out.println("method phone");
}
public static void function()
{
System.out.println("function phone");
}
public void call()
{
System.out.println("打电话");
}
}
class NewPhone extends Phone
{
private void show()
{
System.out.println("private newphone");
}
/*
void method()
{
System.out.println("method phone");
}报错,因为父类为public void method()而子类是void method()为默认的访问权限,
默认的访问权限不如public权限大,所以有报错。

public  void function()
{
System.out.println("function newphone");
}
报错,因为父类为静态的,子类为非静态的,静态只能覆盖静态。
如相反,父类为非静态,子类为静态也不可以。
因为静态随着类的加载而加载,而非静态随着对象的加载而加载。
*/
public void call()
{
System.out.println("播放彩铃");
super.call();//super.方法名可以调用父类定义过的方法。
}
}
class ExtendsDemo5 
{
public static void main(String[] args) 
{
NewPhone np = new NewPhone();
np.call();   
}

}

6、继承中的构造关系:
子类的构造方法默认都去访问了父类的无参构造方法:
在子类中的构造方法都有一行默认的语句:super()
即使是有参构造,在访问有参构造之前还是要访问无参构造。
为什么这么做呢?
因为构造函数是进行数据初始化的,在执行构造函数时会对数据进行初始化和赋初始值。
因为在子类中会用到父类中的数据,如果不访问父类的构造方法,就不能对父类的变量初始化和赋值,
构造的作用就是对成员变量初始化,调了构造方法后,会对成员变量由上而下初始化。
那子类就不能使用父类的数据。

注意:
当父类中有有参构造方法,而没有无参构造方法,那么怎么办?
因为如果不给构造方法系统会默认一个无参构造,但是类中有了有参构造,系统将不在提供无参构造。
又因为子类的构造方法默认都要访问父类的无参构造,在父类没有无参构造使就会报错。
解决方案:
A:可以通过super(参数)去访问父类中的带参构造方法。
  super(参数)会使得子类不去访问默认的父类中的无参构造,而变为访问父类的有参构造。
  不管是无参构造还是有参构造都会进行数据的初始化赋值。

B:可以通过this(参数)访问本类中的构造方法。

        代码如下:

        class Fu{

public Fu()
{
   System.out.println("fu");
}
 
//父类的带参构造
public Fu(int a)
{
System.out.println("fu"+a);
}
}
class Zi extends Fu
{
public Zi()
{
//super(20);
System.out.println("zi");
}
//子类的带参构造 
public Zi(int a)
{
//super(a); 
System.out.println("zi"+a);
}
public Zi(int a,int b)
{
//super();
//this();这样访问的是public Zi()
        this(20);//这样访问的是public Zi(int a)
/*
注意在子类中的所有构造方法中至少有一个访问父亲中的构造方法,
以使变量初始化。
*/
System.out.println("zi"+a);
}

}
class ExtendsDemo6 
{
public static void main(String[] args) 
{
Zi z = new Zi();
         Zi z2 = new Zi(30);
  
/*
输出结果是以及执行结果:
          fu:Zi z = new Zi();执行这句话时,遇到子类中默认的super()
      进而访问父类的无参构造,所以输出fu
  zi:然后访问子类的无参构造,输出zi
  fu;Zi z2 = new Zi(20);执行这句话时,仍要首先访问父类的无参构造,输出fu
  zi20:然后访问子类的有参构造,输出zi20

若将父类的无参构造去掉,采用super(参数)去访问父类中的带参构造方法,则结果:
fu20:执行Zi z = new Zi();遇到super(20);访问父类的有参构造,输出fu20.
zi:  然后访问子类的无参构造,输出zi
fu30:执行Zi z2 = new Zi(30);遇到super(a);访问父类中的带参构造,输出fu30.
zi30:然后执行子类的带参构造。
*/
}

}

7、代码块:

1)/*
如果一个类中有静态代码块,构造代码块,构造方法,那么执行顺序是:
静态代码块》构造代码块》构造方法。
因为静态是随着类的加载而加载的,而构造方法和构造代码块随着对象的创建而执行。

*/
class Zi
{
//静态代码块
static
{
System.out.println("静态代码块");
}
//构造代码块
{
System.out.println("构造代码块");

}
//构造方法
public Zi()
{
System.out.println("构造方法");
}
}
class BlockCodeDemo 
{
public static void main(String[] args) 
{
Zi z = new Zi();
Zi z2 = new Zi();
/*
输出结果:
静态代码块
构造代码块
构造方法
构造代码块
构造方法
当创建两个对象时,静态代码块只执行一次,而构造代码块和构造方法执行两次。
*/
}

2)有继承时的代码快执行顺序:

class Fu
{
//静态代码块
static
{
System.out.println("fu静态代码块");
}
//构造代码块
{
System.out.println("fu构造代码块");

}
//构造方法
public Fu()
{
System.out.println("fu构造方法");
}
}
class Zi extends Fu
{
//静态代码块
static
{
System.out.println("zi静态代码块");
}
//构造代码块
{
System.out.println("zi构造代码块");

}
//构造方法
public Zi()
{
System.out.println("zi构造方法");
}
}
class BlockCodeDemo2 
{
public static void main(String[] args) 
{
Zi z = new Zi();
/*创建一个对象时执行结果:
fu静态代码块
zi静态代码块
fu构造代码块
fu构造方法
zi构造代码块
zi构造方法
           分析:Zi z = new Zi();使得执行子静态代码块之前首先执行父类静态代码块,
         然后是子类静态代码块,
然后是父类构造代码块--fu构造方法--zi构造代码块--zi构造方法。
*/
        Zi z2 = new Zi();
/*
当创建两个对象时,输出结果如下:
fu静态代码块
zi静态代码块
fu构造代码块
fu构造方法
zi构造代码块
zi构造方法
fu构造代码块
fu构造方法
zi构造代码块
zi构造方法
*/
}
}

8、一个完整的有父子关系的内存图:

笔记之java基础--08

分析:首先编译生成三个class,接着点执行的时候,首先会加载有main方法的Test类(加载的代码存在代码区,然后在一个一个分配出来)。虚拟机调用main方法,所以main进栈内存;然后走Zi z = new Zi( ),这个时候需要加载Zi类,因为Zi类继承Fu类,所以先加载父类。在加载父类的时候不加载普通方法,只加载静态方法(包括静态代码块等),然后加载子类的静态方法(并执行静态代码块)。接下来执行new Zi( )的动作,这个时候会在堆内存执行,对子类数据进行初始化即走子类的构造方法,但是需要先走父亲的构造方法,这时候加载父类的构造方法(注意:在new ZI()的时候,会走父类构造方法,但是不是创建父类对象,只是把父类构造方法当成普通的方法调用),即对父类进行初始化,num = 10,并通过super使得子类与父类产生关系。然后对子类进行初始化,并将地址只赋给变量z。这是完成加载工作。

9、如果成员变量被私有了,那么在子类中怎么使用?
A:儿子通过父亲的set方法可以给父亲的成员变量赋值。
B:通过子类调用父类的带参构造方法。
class Person
{
private String name;
private int age;

public Person(){}
public Person(String name,int age)
{
this.name = name;
this.age = age;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setAge(int age)
{
this.age = age;
}
public int getAge()
{
return age;
}
public void show()
{
System.out.println(name+"----"+age);
}
}
class Student extends Person
{
public Student(){}

public Student(String name,int age)
{
super(name,age);
}
}
class Teacher extends Person 
{
}
class PrivateTest 
{
public static void main(String[] args) 
{
//测试person类
//方式1
Person p = new Person();
p.setName("林青霞");
p.setAge(26);
p.show();

//方式2
Person p2 = new Person("林志颖",39);
p2.show();

//测试Student类
//方式1
Student s = new Student();
s.setName("高圆圆");
s.setAge(35);
s.show();
//方式2
                 Student s2 = new Student("吴孟达",50);
s2.show();

}

10、final

/*
很多时候有些内容是不能被子类重写的,而有些时候,
只要方法声明相同(public void show()),子类就可以重写父亲的方法,这样就让父亲的方法不安全了。
针对这种情况,我们如果能做一个标记,告诉别人这个方法是不可以被重写的。
那么这个标记是什么呢?final
final关键字:最终的意思,它可以修饰类,修饰成员变量,修饰成员方法.
它修饰的成员方法,是不可以被子类重写的。
它修饰的成员变量其实是一个常量。
常量:
子面值常量‘a’,"123",123
定义常量
和定义变量的格式一致。
它修饰的类,不能被继承。
*/
class Fu
{
final int  x = 10;
public final void show()
{
System.out.println("这是一个绝密文件");
}
}
class Zi extends Fu
{
/*
public void show()
{
System.out.println("这是一堆垃圾");
}
*/ //报错:因为show不能被重写
public void method()
{
//x = 20;报错:因为x不能被修改,类似于常量。
System.out.println(x);
}

}
class  FinalDemo
{
public static void main(String[] args) 
{
Zi z = new Zi();
        z.show();
z.method();
}
}