A4第四章第2节null和成员变量、局部变量的不同初始化

A4第四章第2节null和成员变量、局部变量的不同初始化第4节
1、null表示变量没有指向任何对象
如:Person p=null;
p.sayHello();//结果会抛出异常
2、对于一个为【null的变量】调用【成员方法】都会报异常NullReferenceException。

3、值类型(ValueType):数值类型(int、long、double等)、boolean等基本类型,枚举、结构体。不能为null。String不是值类型。


public void setAge(int age)

{

this.age = age;

}

1、局部变量【必须初始化】,成员变量声明时【默认初始化】,基本数值类型【默认初始值为int】,String等非基本类型【初始化为null】。why?涉及到栈内存和堆内存,以后讲。

 A4第四章第2节定义类字段方法及实例化类

第四章第2节
1、字段不加public,定义的方法加public
2、方法一般是大写开头

3、最简单的类:class Person{}

4、增加类变量(字段)(成员变量)和方法:


class Person{
private int age;//成员变量
private String name;
public void setAge(int age1)//定义的方法setAge方法,age1为传入的变量
{
this.age = age1;
}
public void setName(String name1)//定义setName方法,name1为传入的变量
{
this.name = name1;
}
public void sayHello()//定义sayHello方法
{
Console.WriteLine("大家好,我是"+name+",我今年"+age+"岁了");
}
//再提供get方法
}

 

 

 


5、类的实例化:


Person lzy = new Person();//
lzy.setName("林志颖");
lzy.setAge(80);
lzy.sayHello();
//两个对象的内存分配:根据模板拷贝两份。
yzk.sayHello();
new出的每个对象都是一个单独的实例,两个对象之间的成员变量是独立的两份。new出来的叫【类对象】或者【实例(Instance)】。
6、我们定义一个【类】后,就必须实例化才能使用。【实例化】就是创建一个【对象】的过程。
在C#中,我们使用new运算符关键字来创建。
7、 类 对象=new 类();
即 class object=new class();
即Person xcl=new Person();
8、比如有一个类叫汽车。你现在想在程序中买一辆,所以你用new来买了一辆汽车,这辆车你得给它找个名字,
比如宝马。
例如:汽车 宝马 = new 汽车();

你有钱了,你要再来一辆:

汽车 奔驰 = new 汽车();

A4第四章第5节this解决成员变量和局部变量重名的问题

第四章第5节
1、当成员变量和局部变量(函数参数也可以看做局部变量)重名的时候,被看做局部变量,因此为了避免混乱,建议访问成员变量的时候加上“this.”,this代表当前对象。

2、new Person().sayHello();创建一个匿名对象,然后调用。输出结果是?
new Person().sayHello();
等价于
Person t=new Person();
t.sayHello();
3、【类】里边定义的变量是成员变量,【方法】里边定义变量叫做局部变量

A4第四章第6节public和private

第四章第6节
1、我们可以把age成员变量声明为public,也可以把setAge声明为private,这样就只能在【类内部】调用private成员(再写一个方法调用private的setAge)

2、结论:public成员可以【被类内部或者外部】访问,private成员【只能被类内部】访问。这样可以保护不希望外接调用的内部成员(Member,包含字段Field/变量、方法)不被外界访问。

3、直接通过public的age设置年龄,不通过setAge赋值,这样有什么坏处?-1。【不能有效控制非法字符的赋值】

4、字段(Field)/成员变量(Member Variable)一般声明为private。通过get/set方法来进行取值/赋值。

A4第四章第7节属性入门

第四章第7节
1、为了避免外界给成员变量随便赋值,必须把成员变量声明为private,然后提供get/set方法,写起来、调用起来都麻烦,C#提供了“属性”这样一个语法:

private int height;//成员变量
public int Height//写成大写格式,方便外界调用属性值//如果改为private则只能在内部调用
{
get
{
return this.height;
}
set
{
this.height = value;
}
}
p.Height=50;//相当于调用【set方法对p的Height进行【赋值】
int a = p.Height;//相当于调用【get方法对p的Height进行【取值】


通过Reflector看属性本质上是什么?( ILSpy的C#看的优化后的代码,IL看的是IL代码,看不懂 )

public void set_Height(int value)//反编译中查看的代码set
{
this.height = value;
}
public int get_Height()//反编译中查看的代码get
{
return this.height;
}

A4第四章第8节 属性的简化写法

第四章第8节
1、//如果是简单地set。get逻辑,暂时没有更多的逻辑代代码,可以简化如下;
public string Name
{
get;
set;
}
2、Reflector反编译器
查看PropertyTest1.exe--{}propertyTest1-Name:string
发现显示的语法其实还是以前讲的定义的
public void getAge(int Age)
{
return this.Age;
}
public void setAge(int Age)
{
this.Age=Age;
}

1、如果是简单set/get逻辑,可以使用更简写的语法: public int Weight { get; set; } 通过Reflector看本质是什么

2、get、set可以有一个声明为private、protected,这样就可以设置不同的访问级别。

3、如果只有get或者set就是只读或只写属性。只读只写【不能简化写】。

A4第四章第9节 构造函数入门和属性赋值的简化写法

第四章第9节
1、构造函数是创建类对象,并且在创建完成前对类进行初始化的特殊函数。如果定义类时没有声明构造函数,【默认】会给出一个无参构造函数,如果定义了任意一个构造函数,将【不会】提供默认的无参构造函数。

2、构造方法/函数格式及特点:

方法名【必须】和类名一致

【没有】返回值类型

构造函数可以重载,Person(String name,int age)

3、
class Person
{
public int Id { get; set; }//id属性
public string Name { get; set; }//Name属性
public int Age { get; set; }//Age属性
public Person()//默认的构造函数【也可以不写,但是通过反编译器会看到它是默认存在的】
{
}
public Person(int id)//构造id函数,给id进行初始化、、它的存在会使默认的构造函数失去。除非。你申明了默认构造函数
{
this.Id = id;
}
}
Person p = new Person() { Id=5,Name="abc"};//new出来一个新的对象,并且赋值id和Name
Person p1 = new Person(5) { Name = "aaa", Age = 12};//Person后的括号中的5其实是初始化年龄为5,花括号内的Age又重新对new出的对象赋值了12
Person p2 = new Person { Id=5,Name="a"};//Person后的括号可以省去,但是最好不要省去


通过ILSpy反编译看一下,还是一个编译器玩的“语法糖”,所以和构造函数不一样,赋值是在对象构造之后

A4第四章第10节static介绍

第四章第10节
1、一些场景下会要求一个类的多个实例共享一个成员变量;有时候想定义一些不和具体对象关联、不需要new就调用的方法

举例:Console类的WriteLine,MessageBox的Show

2、static方法不需要new就可以直接通过类名调用。

3、static变量不需要new就可以直接通过类名调用。static变量是共享的内存空间,非static变量则是对象隔离的。

4、static 方法中无法使用this关键字,因为static独立于对象存在,不是任何人的唯一。

5、static成员中只能访问static成员,不能直接访问非static成员。非static成员可以访问static成员。

A4第四章第11节单例模式

第四章第11节
1、有的类在系统中只能有一个对象(*,资源管理器、缓存管理器等),这时就要使用“单例模式”(singleton)。实现单例模式有很多方法,先介绍最简单、最实用的“饿汉式”。

2、单例模式的实现步骤:

1)构造函数声明为private,这样避免外界访问

2)定义一个private readonly static的对象实例,static成员的初始化只在类第一次使用的时候执行一次。readonly修饰变量只能在构造函数或者初始化的时候赋值。

3)定义一个public static的getInstance方法,返回唯一实例。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SingletonTest1
{
class God
{
//静态变量的初始化只执行一次
private static God Instance = new God();

private God() { }//构造函数声明为private,避免外界调用

public void ZhaoYaoDaDi()
{
Console.WriteLine("照耀");
}

public static God GetInstance()
{
return Instance;
}
}
}

 A4第四章第12节静态代码块以及面试题

第四章第12节
class MyTest
{
static MyTest()
{
Console.WriteLine("zi 静态代码块");
}
public MyTest()
{
Console.WriteLine("zi 构造方法");
}
}
MyTest t1 = new MyTest();
MyTest t2 = new MyTest();
【静态代码块在类第一次被使用的时候执行一次,在构造函数执行之前执行。【只要用到类】,哪怕没new对象(比如只是声明变量)也会被执行,且只执行一次。

 

public class MyJingTaiDaimaKuai
{
public static int i = test1();//最开始执行
public int age = test2();//new的时候先执行成员变量的初始化,再执行构造函数

static MyJingTaiDaimaKuai()
{
Console.WriteLine("静态代码块");//再执行
}
public MyJingTaiDaimaKuai()
{
Console.WriteLine("构造函数");
}

public static int test1()
{
Console.WriteLine("test1");
return 3;
}

public static int test2()
{
Console.WriteLine("test2");

return 333;
}
}

MyJingTaiDaimaKuai a1 = new MyJingTaiDaimaKuai();
Console.WriteLine(a1.age);

MyJingTaiDaimaKuai a2 = new MyJingTaiDaimaKuai();
Console.WriteLine(a2.age);


【一般用于对类进行初始化,以后会用

只要一旦开始“接触一个类”,静态成员、static代码块就会被执行】

A4第四章第13节命名空间

第四章第13节
用文件系统的文件夹解释避免文件名重复的问题。

命名空间语法:

namespace ConsoleApplication1包住类;

当前命名空间中的类无需引用;使用using引用其他包中的类:

还可以直接通过“命名空间+类名”的方式使用“System.Data.SqlClient.SqlConnection”,不用using,适用于同时使用多个重名的类,比using时候的别名好;

A4第四章第14节继承基本语法

第四章第14节
C#中一个类可以“继承”自其他类,如果A继承自B,则A叫做B的子类,B叫做A的父类(基类)。子类会从父类继承所有非private成员。子类还可以有子类。

C#中一个类只能有一个父类,如果没指定父类,则System.Object为父类。

class FuLei
{
private void method1()
{
}
public void method2()
{
}
}

class ZiLei : FuLei
{
private void method3()
{
}
public void method4()
{
}
}


ZiLei zl1 = new ZiLei();
zl1.method1();
zl1.method2();
zl1.method4();
zl1.toString();

A4第四章第15节继承中的构造函数

第四章第15节
C#中一个类可以“继承”自其他类,如果A继承自B,则A叫做B的子类,B叫做A的父类(基类)。子类会从父类继承所有非private成员。子类还可以有子类。

C#中一个类只能有一个父类,如果没指定父类,则System.Object为父类。


子类的构造方法默认都去访问了父类的【无参构造方法】:在子类中的构造方法后都有一行默认语句 base()


class Fu
{ public Fu()
{
Console.WriteLine("fu");
}
}
class Zi : Fu
{
public Zi()
: base()//不管是否显式调用,控制台都会输出fu
{
Console.WriteLine("zi");
}
}
Zi z = new Zi();
先执行父类的构造函数把父类初始化完成,再初始化子类的。

 

可以通过super(参数)去访问父类中的有参构造函数。可以通过this(参数...)去访问本类中的其他构造函数。


class Fu
{
public Fu(int a)
{
Console.WriteLine("fu"+a);
}
}
class Zi : Fu
{
public Zi():base(0)//为了避免出错,给父类传递一个整数0,来调用父类的有参构造函数
{
Console.WriteLine("zi");
}
public Zi(int a):base(a)//默认会调用父类的无参的构造函数。不过父类中没有无参构造函数,故将a传递给父类的构造函数 public Fu(int a)
{
Console.WriteLine("zi"+a);
}
}
如果定义了构造函数,则类就不会有默认的无参构造函数;如果父类中没有默认的,则子类构造函数必须显示调用父类的构造函数

一个类如果没有定义其他构造函数,则有一个【默认的无参构造函数】。构造函数会默认调用父类的【无参构造函数】
子类的无参或者是有参构造函数都会默认调用父类的【无参构造函数】

A4第四章第16节 private、public和protected的区别 

第四章第16节
private成员无法被子类访问,子类只能通过父类的非private方法“间接”访问父类的private成员。这样保证了父类private成员的安全性。

procected成员只能被自己以及子类(直接或者间接)访问,无法被“外姓人”访问。

A4第四章第17节 Override

第四章第17节
面向对象三大特征:封装、继承、多态。多态是面向对象最强大的一个特征,也是最难的一个特征,设计模式等都是多态的体现。大型项目架构也大量应用多态。

子类中定义和父类中一样的方法就叫“重写(Override)或覆盖”,父类中可以被Override方法要声明为virtual 。Override和OverLoad区别见备注


class DiQiuRen
{
public virtual void speak(){Console.WriteLine("我是地球人");}
}
class Chinese : DiQiuRen
{
public override void speak(){Console.WriteLine("我是中国人");}
public void baiNian(){Console.WriteLine("过年好!");}
}
DiQiuRen dqr1 = new DiQiuRen();
dqr1.speak();
Chinese zgr1 = new Chinese();
zgr1.speak();

 

面试常考:
OverLoad:重载,方法的名字一样,参数的类数的个数或者类型不一样。
OverRide:重写,子类有和父类一样(名字,参数个数,类型,返回值)的方法(非private)

A4第四章第18节 多态的精髓

第四章第18节
1、不能用【子类的变量】指向【父类的对象】
例如:Chinese zgr2=new DiQiuRen();//地球人不一定是中国人
2、可以用【父类的变量】指向【子类的对象】
例如:DiQiuRen dqr2=new Chinese();//中国人一定是地球人
3、调用方法还是对象的方法,而不是变量类型的实现
4、记住::【【能够调用什么方法由变量类型决定,执行谁的方法由实际指向的对象决定】】
DiQiuRen dqr1=new Chinese();
DiQiuRen 是变量类型,,Chinese是指向的对象

下面的执行结果是什么??
Chinese zgr2=new DiQiuRen();//地球人不一定是中国人
DiQiuRen dqr2=new Chinese();//中国人一定是地球人
dqr2.sayHello();//实际上执行的是Chinese里的sayHello而不是DiQiuRen里的sayHello方法。。执行谁的方法由实际指向的对象决定

5、变量类型是“把对象看成什么”,DiQiuRen dqr2=new Chinese()是把Chinese对象看成是“地球人”,因为“地球人”不一定有baiNian方法,因此dqr2.baiNian()编译失败。

A4第四章第19节 多态与类型转换

第四章第19节
1、编译器只看类型,无法看实际是什么对象
2、ZGR zgr2=(ZGR)dqr2//显示转换..父类显示转换为子类
3、

下面程序的执行结果是什么?

Chinese zgr5 = (Chinese)dqr2;

zgr5.sayHello();

zgr5.baiNian();

Chinese zgr5 = (Chinese)dqr1;

()类型转换可以把“被看做父类对象的实例”重新看成“子类”。(显式类型转换/强制类型转换)

如果对象就是父类对象,当被看成子类对象的时候会失败,抛出运行期异常,编译器无法发现这个错误。

类型转换只能在有父子关系的类中进行

思考:

1、定义一个方法 void test1(DiQiuRen dqr){dqr.sayHello();}

如下调用test1(new Chinese());可以吗?运行结果是什么?

2、String s = (String)zgr1;可以吗?

 

A4第四章第20节抽象类

第四章第20节
1、把类标记为abstract,这样的类无法被直接实例化(new),这就叫抽象类。

2、DiQiuRen的sayHello输出“我是地球人”显然不合理,因为无法确定怎么说,也就是DiQiuRen不知道如何sayHello, 只有具体到中国人、日本人、美国人才知道如何sayHello

3、把DiQiuRen的sayHello的方法体去掉,并且方法增加abstract修饰,类也修饰为abstract:

abstract class DiQiuRen

{

public abstract void speak();//没有方法体的抽象方法

}

4、抽象方法没有方法体;一旦类中定义了抽象方法,类必须被修饰为抽象;抽象类无法实例化(new)。
5、抽象类中不一定有抽象方法

A4第四章第21节接口

第四章第21节接口
1、接口是一种用来声明“能力”的类型,不提供具体实现

语法:

public interface ISpeakable

{

void speak();

}

2、不提供实现方法,连{}都不能有。

3、接口无法实例化,只能被类“实现”

public class TeacherCang : ISpeakable

{

}

4、既可以使用接口类型变量又可以使用类类型变量调用speak

5、接口的意义是定义“做什么”,类定义“怎么做”

6、接口中不能声明变量(字段),一个没有实现代码的接口中声明变量没意义。

7、接口中可以定义多个方法,也可以不定义任何方法(* 标识接口)。

8、接口只是“能力”不是“实现”,因此不能也没必要定义构造函数。

9、类只能有一个父类,类可以实现多个接口。测试一下:Speakable、Walkable。

**************************************************************************************
接口和抽象类的区别和联系(常见面试题,自己先看看)

 

1、抽象类里面可以有非抽象方法
但接口里只能有抽象方法
声明方法的存在而不去实现它的类被叫做抽像类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其类型是一个抽像类,并让它指向具体子类的一个实例。不能有抽像构造函数或抽像静态方法。Abstract 类的子类为它们父类中的所有抽像方法提供实现,否则它们也是抽像类为。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。

2、接口(interface)是抽像类的变体。在接口中,所有方法都是抽像的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽像的,没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对像上调用接口的方法。由于有抽像类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否实现了接口

 

posted @ 2015-05-12 15:00  t800  阅读(181)  评论(0)    收藏  举报