应用程序唯一性

程序启动后,如果再次启动程序,不会出现2个程序,或者实现如Notepad++已打开一个文件,再打开另外一个文件,则追加在Notepad++界面上。

使用codeproject上别人编写的一个类,加在程序启动时即可。

sinstance.h

/*
Module : SINSTANCE.H
Purpose: Defines the interface for an MFC wrapper class to do instance checking
Created: PJN / 29-07-1998

Copyright (c) 1996 - 2008 by PJ Naughter (Web: www.naughter.com, Email: [email protected])

All rights reserved.

Copyright / Usage Details:

You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
when your product is released in binary form. You are allowed to modify the source code in any way you want
except you cannot modify the copyright details at the top of each module. If you want to distribute source
code with your application, then you are only allowed to distribute versions released by the author. This is
to maintain a single distribution point for the source code. 

*/

/////////////////////////// Macros / Defines //////////////////////////////////

#pragma once

#ifndef __SINSTANCE_H__
#define __SINSTANCE_H__

#ifndef CSINGLEINSTANCE_EXT_CLASS
#define CSINGLEINSTANCE_EXT_CLASS
#endif

#ifndef CSINGLEINSTANCE_EXT_API
#define CSINGLEINSTANCE_EXT_API
#endif

//////////////////////////// Includes /////////////////////////////////////////

#ifndef __AFXMT_H__
#pragma message("To avoid this message, please put afxmt.h in your pre compiled header (normally stdafx.h)")
#include <afxmt.h>
#endif

//////////////////////////// Classes //////////////////////////////////////////

class CSINGLEINSTANCE_EXT_CLASS CInstanceChecker
{
public:
//Constructors / Destructors
	CInstanceChecker(const CString& sUniqueName);
	virtual ~CInstanceChecker();

//General functions
	void ActivateChecker();
	BOOL TrackFirstInstanceRunning();
	BOOL PreviousInstanceRunning();
	HWND ActivatePreviousInstance(LPCTSTR lpCmdLine = NULL, ULONG_PTR dwCopyDataItemData = 0, DWORD dwTimeout = 30000);
	void QuitPreviousInstance(int nExitCode = 0);

protected:
//Virtual methods
	virtual CString GetMMFFilename();
	virtual HWND GetWindowToTrack();

//Standard non-virtual methods
  void ReleaseLock();

//Data
	CMutex       m_instanceDataMutex;
	CMutex       m_executeMutex;
	CSingleLock* m_pExecuteLock;
  CString      m_sName;
};

#endif //__SINSTANCE_H__

  sinstance.cpp

/*
Module : SINSTANCE.CPP
Purpose: Defines the implementation for an MFC wrapper classe
         to do instance checking
Created: PJN / 29-07-1998
History: PJN / 25-03-2000 Neville Franks made the following changes. Contact [email protected], www.getsoft.com
                          1. Changed #pragma error to #pragma message. Former wouldn‘t compile under VC6
                          2. Replaced above #pragma with #include
                          3. Added TrackFirstInstanceRunning(), MakeMMFFilename()
         PJN / 27-03-2000 1. Fixed a potential handle leak where the file handle m_hPrevInstance was not being
                          closed under certain circumstances.
                          Neville Franks made the following changes. Contact [email protected], www.getsoft.com
                          2. Split PreviousInstanceRunning() up into separate functions so we
                          can call it without needing the MainFrame window.
                          3. Changed ActivatePreviousInstance() to return hWnd.
         PJN / 15-05-2000 1. Serialized access to all of the CSingleInstance class to prevent race conditions
                          which can occur when you app is programatically spawned.
         PJN / 17-05-2000 1. Updated sample to show how the code can be used for dialog based apps.
         PJN / 01-01-2001 1. Added a number of asserts to CInstanceChecker::ActivatePreviousInstance
                          2. Now includes copyright message in the source code and documentation.
         PJN / 15-01-2001 1. Now allows multiple calls to PreviousInstanceRunning without ASSERTing
                          2. Removed some unnecessary VERIFY‘s from ActivatePreviousInstance
                          3. Made the MMF filename used modifiable via a virtual function GetMMFFilename
                          4. Made the window to track modifiable via a virtual function GetWindowToTrack
                          5. Made destructor virtual since the introduction of other virtual functions in the class
                          6. Removed a number of unnecessary verifies
                          7. Changed the meaning of the return value from TrackFirstInstanceRunning
         PJN / 17-06-2001 1. Moved most of the code from CInstanceChecker::CInstanceChecker to
                          CInstanceChecker::ActivateChecker. This allows client code to turn on or off the instance
                          checking code easily. Thanks to Anders Rundegren for this addition.
         PJN / 31-08-2001 1. made the name of the mutex which the class uses to serialize access to itself a paramter
                          to the constructor. That way multiple independent apps do not block each other while
                          they are calling into the CSingleInstance class. Thanks to Eugene Shmelyov for spotting
                          this problem.
         PJN / 23-03-2002 1. Provided a QuitPreviousInstance method. Thanks to Jon Bennett for providing this.
         PJN / 30-10-2002 1. The name of the internal memory mapped file is now based on the Mutex name rather than
                          the application name. An example: a client was writing a webcam application and wanted it to
                          run with multiple configuration for multiple camera support. So the app can run multiple times
                          as long as a special configuration is given on the command line. But for that configuration
                          only one instance is allowed. Using the application name for the memory mapped file was tying
                          the single instance to the app rather than the unique mutex name. Thanks to Frank Fesevur for
                          this nice update.
         PJN / 06-02-2003 1. Was missing a call to ReleaseLock in CInstanceChecker::ActivatePreviousInstance. Thanks to
                          Pierrick Ingels for reporting this problem.
         PJN / 09-05-2004 1. Updated the copyright details.
                          2. Extended CInstanceChecker::ActivatePreviousInstance to now allow the command line of the
                          second app to be passed to the original app. By default the parameter is NULL, meaning that
                          you get the original behaviour which just activates the previous instance. To respond to this
                          information you should add the following to your mainfrm module:

                          mainfrm.h

                          afx_msg LRESULT OnCopyData(WPARAM, LPARAM);

                          mainfrm.cpp

                          LRESULT CMyFrameWnd::OnCopyData(WPARAM wParam, LPARAM lParam)
                          {
                            COPYDATASTRUCT* pCDS = reinterpret_cast<COPYDATASTRUCT*>(lParam);
                            TCHAR* pszCmdLine = static_cast<TCHAR*>(pCDS->lpData);
                            if (pszCmdLine)
                            {
                              //DO SOMETHING with pszCmdLine here such as call AfxGetApp()->OpenDocumentFile(pszCmdLine);
                            }
                            return TRUE;
                          }

                          Also hook up your onCopyData to the windows message map using

                          ON_MESSAGE(WM_COPYDATA, OnCopyData)

                          Thanks to Ingo H. de Boer for providing this nice update.

                          3. Following a discussion on the Codeproject.com discussion forum for CSingleInstance on what
                          exactly a single instance app means (See http://www.codeproject.com/cpp/csingleinst.asp?msg=766108#xx1103xx),
                          Daniel Lohmann has produced a simple function called CreateUniqueName which given a number of
                          settings as flags, will produce a name which is unique. This code can be downloaded at
                          http://www.losoft.de/code/SingleInstance.zip. You can then use this name in the constructor for
                          CInstanceChecker. The concept of a single instance app is complicated by the concept of Window stations
                          and desktops as used by NT Services and Windows Terminal Services. In addition you might want to allow your
                          program to be run once per user.
         PJN / 30-05-2005 1. Fix for a crash where CWnd::GetLastActivePopup can sometimes return a NULL pointer. Thanks to
                          Dominik Reichl for reporting this bug.
         PJN / 07-07-2006 1. Updated copyright details.
                          2. Addition of CSINGLEINSTANCE_EXT_CLASS and CSINGLEINSTANCE_EXT_API which allows the class to be easily used
                          in an extension DLL.
                          3. Removed derivation from CObject as it was not really needed.
                          4. Updated the documentation to use the same style as the web site.
                          5. Code now uses newer C++ style casts instead of C style casts.
                          6. Fixed a number of level 4 warnings in the sample app.
                          7. Updated code to compile cleanly using VC 2005.
         PJN / 17-03-2007 1. Updated copyright details.
                          2. Optimized _INSTANCE_DATA constructor code
                          3. Reworked how the method CInstanceChecker::GetMMFFilename creates the name of the memory mapped filename
                          the code requires for sharing. Now the main instance name appears before the hard coded string. This
                          ensures that the CInstanceChecker class works correctly for terminal sessions i.e. kernel objects prefixed
                          with the value "Local\". Thanks to Mathias Berchtold for reporting this issue.
                          4. Updated the sample app code to clean compile on VC 2005
                          5. QuitPreviousInstance now uses GetLastActivePopup API to ensure it posts the WM_QUIT message to the
                          correct window of the previous instance.
         PJN / 02-02-2008 1. Updated copyright details
                          2. Removed VC 6 style classwizard comments from the sample apps code
                          3. Updated ActivatePreviousInstance method to support Win64 compliant data
                          4. ActivatePreviousInstance now takes a "dwTimeout" parameter which it now uses internally as the timeout when
                          calling SendMessageTimeout instead of SendMessage. The code now uses SendMessageTimeout instead of SendMessage
                          to ensure we do not hang if the previous instance itself is hung. Thanks to Paul Shore for suggesting this
                          update.
                          5. Updated the sample apps to clean compile on VC 2008

Copyright (c) 1996 - 2008 by PJ Naughter (Web: www.naughter.com, Email: [email protected])

All rights reserved.

Copyright / Usage Details:

You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
when your product is released in binary form. You are allowed to modify the source code in any way you want
except you cannot modify the copyright details at the top of each module. If you want to distribute source
code with your application, then you are only allowed to distribute versions released by the author. This is
to maintain a single distribution point for the source code. 

*/

/////////////////////////////////  Includes  //////////////////////////////////

#include "stdafx.h"
#include "sinstance.h"

/////////////////////////////// Defines / Macros //////////////////////////////

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

///////////////////////////////// Implementation //////////////////////////////

//struct which is put into shared memory
struct CWindowInstance
{
  HWND hMainWnd;
};

//Class which is used as a static to ensure that we
//only close the file mapping at the very last chance
class _SINSTANCE_DATA
{
public:
//Constructors / Destructors
  _SINSTANCE_DATA();
  ~_SINSTANCE_DATA();

protected:
//Member variables
  HANDLE hInstanceData;

  friend class CInstanceChecker;
};

_SINSTANCE_DATA::_SINSTANCE_DATA() : hInstanceData(NULL)
{
}

_SINSTANCE_DATA::~_SINSTANCE_DATA()
{
  if (hInstanceData != NULL)
  {
    ::CloseHandle(hInstanceData);
    hInstanceData = NULL;
  }
}

static _SINSTANCE_DATA g_sinstanceData;

CInstanceChecker::CInstanceChecker(const CString& sUniqueName) : m_executeMutex(FALSE, sUniqueName)
{
  //Hive away the unique name as we will also be using it for the name of the memory mapped file
  m_sName = sUniqueName;

  //Only one object of type CInstanceChecker should be created
  ASSERT(g_sinstanceData.hInstanceData == NULL);
  m_pExecuteLock = NULL;
}

void CInstanceChecker::ActivateChecker()
{
  ASSERT(m_pExecuteLock == NULL);

  //Ensure there is only ever one CInstanceChecker instance
  //active at any one time throughout the system
  m_pExecuteLock = new CSingleLock(&m_executeMutex, TRUE);
}

CInstanceChecker::~CInstanceChecker()
{
  //Free up the instance lock
  ReleaseLock();
}

void CInstanceChecker::ReleaseLock()
{
  if (m_pExecuteLock)
  {
    delete m_pExecuteLock;
    m_pExecuteLock = NULL;
  }
}

//Track the first instance of our App.
//return TRUE on success, else FALSE
BOOL CInstanceChecker::TrackFirstInstanceRunning()
{
  //If a previous instance is running, just return prematurely
  if (PreviousInstanceRunning())
    return FALSE;

  //If this is the first instance then copy in our info into the shared memory

  //First create the MMF
  int nMMFSize = sizeof(CWindowInstance);
  g_sinstanceData.hInstanceData = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, nMMFSize, GetMMFFilename());
  if (g_sinstanceData.hInstanceData == NULL)
  {
    TRACE(_T("Failed to create the MMF even though this is the first instance, you might want to consider overriding GetMMFFilename()\n"));
    return FALSE;
  }

  //Open the MMF
  CWindowInstance* pInstanceData = static_cast<CWindowInstance*>(MapViewOfFile(g_sinstanceData.hInstanceData, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, nMMFSize));
  ASSERT(pInstanceData != NULL);   //Opening the MMF should work

  //Lock the data prior to updating it
  CSingleLock dataLock(&m_instanceDataMutex, TRUE);
  pInstanceData->hMainWnd = GetWindowToTrack();
  UnmapViewOfFile(pInstanceData);

  //Since this will be the last function that will be called
  //when this is the first instance we can release the lock
  ReleaseLock();

  return TRUE;
}

// Returns TRUE if a previous instance of the App is running.
BOOL CInstanceChecker::PreviousInstanceRunning()
{
  //Try to open the MMF first to see if we are the second instance
  HANDLE hPrevInstance = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, GetMMFFilename());
  BOOL bPreviousInstance = (hPrevInstance != NULL);
  if (hPrevInstance)
    CloseHandle(hPrevInstance);

  return bPreviousInstance;
}

CString CInstanceChecker::GetMMFFilename()
{
  CString sMMF(m_sName);
  sMMF += _T("_CInstanceChecker_MMF");
  return sMMF;
}

HWND CInstanceChecker::GetWindowToTrack()
{
  //By default the window tracked will be the standard AfxGetMainWnd()
  ASSERT(AfxGetMainWnd() != NULL); //Did you forget to set up the mainfrm in InitInstance ?
  return AfxGetMainWnd()->GetSafeHwnd();
}

//Activate the Previous Instance of our Application.
HWND CInstanceChecker::ActivatePreviousInstance(LPCTSTR lpCmdLine, ULONG_PTR dwCopyDataItemData, DWORD dwTimeout)
{
  //What will be the return value from this function (assume the worst)
  HWND hWindow = NULL;

  //Try to open the previous instances MMF
  HANDLE hPrevInstance = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, GetMMFFilename());
  if (hPrevInstance)
  {
    //Open up the MMF
    int nMMFSize = sizeof(CWindowInstance);
    CWindowInstance* pInstanceData = static_cast<CWindowInstance*>(MapViewOfFile(hPrevInstance, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, nMMFSize));
    if (pInstanceData) //Opening the MMF should work
    {
      //Lock the data prior to reading from it
      CSingleLock dataLock(&m_instanceDataMutex, TRUE);

      //activate the old window
      ASSERT(pInstanceData->hMainWnd); //Something gone wrong with the MMF
      hWindow = pInstanceData->hMainWnd;
      if (hWindow)
      {
        CWnd wndPrev;
        wndPrev.Attach(hWindow);
        CWnd* pWndChild = wndPrev.GetLastActivePopup();

        //Restore the focus to the previous instance and bring it to the foreground
        if (wndPrev.IsIconic())
          wndPrev.ShowWindow(SW_RESTORE);

        if (pWndChild)
          pWndChild->SetForegroundWindow();

        if (lpCmdLine)
        {
          //Send the current apps command line to the previous instance using WM_COPYDATA
          COPYDATASTRUCT cds;
          cds.dwData = dwCopyDataItemData;
          DWORD dwCmdLength = static_cast<DWORD>(_tcslen(lpCmdLine) + 1);
          cds.cbData = dwCmdLength * sizeof(TCHAR);
          TCHAR* pszLocalCmdLine = new TCHAR[dwCmdLength]; //We use a local buffer so that we can specify a constant parameter
                                                           //to this function
        #if (_MSC_VER >= 1400)
          _tcscpy_s(pszLocalCmdLine, dwCmdLength, lpCmdLine);
        #else
          _tcscpy(pszLocalCmdLine, lpCmdLine);
        #endif
          cds.lpData = pszLocalCmdLine;
          CWnd* pMainWindow = AfxGetMainWnd();
          HWND hSender = NULL;
          if (pMainWindow)
            hSender = pMainWindow->GetSafeHwnd();

          //Send the message to the previous instance. Use SendMessageTimeout instead of SendMessage to ensure we
          //do not hang if the previous instance itself is hung
          DWORD_PTR dwResult = 0;
          if (SendMessageTimeout(hWindow, WM_COPYDATA, reinterpret_cast<WPARAM>(hSender), reinterpret_cast<LPARAM>(&cds),
                                 SMTO_ABORTIFHUNG, dwTimeout, &dwResult) == 0)
          {
            //Previous instance is not responding to messages
            hWindow = NULL;
          }

          //Tidy up the heap memory we have used
          delete [] pszLocalCmdLine;
        }

        //Detach the CWnd we were using
        wndPrev.Detach();
      }

      //Unmap the MMF we were using
      UnmapViewOfFile(pInstanceData);
    }

    //Close the file handle now that we
    CloseHandle(hPrevInstance);

    //When we have activate the previous instance, we can release the lock
    ReleaseLock();
  }

  return hWindow;
}

void CInstanceChecker::QuitPreviousInstance(int nExitCode)
{
  //Try to open the previous instances MMF
  HANDLE hPrevInstance = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, GetMMFFilename());
	if (hPrevInstance)
	{
		// Open up the MMF
		int nMMFSize = sizeof(CWindowInstance);
		CWindowInstance* pInstanceData = static_cast<CWindowInstance*>(MapViewOfFile(hPrevInstance, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, nMMFSize));
		if (pInstanceData != NULL) //Opening the MMF should work
		{
		  // Lock the data prior to reading from it
		  CSingleLock dataLock(&m_instanceDataMutex, TRUE);

		  //activate the old window
		  ASSERT(pInstanceData->hMainWnd); //Something gone wrong with the MMF?
		  HWND hWnd = pInstanceData->hMainWnd;

      //Ask it to exit
      HWND hChildWnd = GetLastActivePopup(hWnd);
  	  PostMessage(hChildWnd, WM_QUIT, nExitCode, 0);
	  }

    //Close the file handle now that we
    CloseHandle(hPrevInstance);
  }
}

  windows MFC下使用方法:

在InitInstance()中添加:
//Check for the previous instance as soon as possible
  CInstanceChecker instanceChecker(_T("CInstanceChecker Example FrameWnd App"));
  instanceChecker.ActivateChecker();
  if (instanceChecker.PreviousInstanceRunning())
  {
    CCommandLineInfo cmdInfo;
    ParseCommandLine(cmdInfo);

	  AfxMessageBox(_T("Previous version detected, will now restore it"), MB_OK);
    instanceChecker.ActivatePreviousInstance(cmdInfo.m_strFileName);
	  return FALSE;
  }

...

  //Standard MFC stuff, create the mainframe
  CFrameWnd* pMainFrm = new CMyFrameWnd();
  if (!pMainFrm->Create(NULL, m_pszAppName))
    return FALSE;
  pMainFrm->ShowWindow(SW_SHOW);
  m_pMainWnd = pMainFrm;

  // If this is the first instance of our App then track it so any other instances can find us
  instanceChecker.TrackFirstInstanceRunning();

  如需实现像Notepad++追加在程序后面的效果,可在CFrameWnd中添加:

添加WM_COPYDATA消息响应

LRESULT CMyFrameWnd::OnCopyData(WPARAM /*wParam*/, LPARAM lParam)
{
  COPYDATASTRUCT* pCDS = reinterpret_cast<COPYDATASTRUCT*>(lParam);
  TCHAR* pszCmdLine = static_cast<TCHAR*>(pCDS->lpData);
  if (pszCmdLine)
  {
    CString sMsg;
    sMsg.Format(_T("Another instance passed us the command line: %s"), pszCmdLine);
    AfxMessageBox(sMsg);
  }
  return TRUE;
}
时间: 2024-10-25 17:38:58

应用程序唯一性的相关文章

python高级编程:有用的设计模式1

# -*- coding: utf-8 -*-__author__ = 'Administrator'#python高级编程:有用的设计模式#设计械是可复用的,某种程序上它对软件设计中觉问题提供的语言相关解决识方案,最近最流行的书籍:"""gamma.heim.johson和vlissides a.k.a"四人组(gof)"编写的elements of reusable object-oriented software(中文:<设计模式:可复用面向对

C# Winform程序以及窗体运行的唯一性汇总

经常看到有人讨论程序运行唯一性或者窗体运行的唯一性问题.我之前也写了一些文章,在此把它进行整理汇总. 如果是程序的唯一性问题,我之前的一篇文章已经写得很全面,可以参看. C# Winform如何使自己的程序只运行一次 如果是MDI子窗体的话,那么我最近的一篇文章提到的两种方法都不错,可以参看. C# Winform如何在MDI中使子窗体只保留一个实例 如果不是MDI子窗体的话,而是一般窗体的话,其实要做到唯一打开的话,其实也是很简单的,需要在窗体中去做一些简单代码即可了. 如下就用一个名叫“fr

QT创建模态对话框阻塞整个应用程序和非模态对话框唯一性约束的简单示例

QT创建模态对话框阻塞整个应用程序和非模态对话框唯一性约束的简单示例 部分代码: // 创建模态对话框阻塞整个应用程序和非模态对话框唯一性约束 QMenu *pDialog = mBar->addMenu(QString::fromLocal8Bit("对话框")); QAction *pTopDialog = pDialog->addAction(QString::fromLocal8Bit("模态对话框")); connect(pTopDialog,

【2017-06-20】Linux应用开发工程师C/C++面试问题之一:Linux多线程程序的同步问题

参考之一:Linux 线程同步的三种方法 链接地址:http://www.cnblogs.com/eleclsc/p/5838790.html 简要回答: Linux下线程同步最常用的三种方法就是互斥锁.条件变量及信号量. 互斥锁通过锁机制来实现线程间的同步,锁机制是同一时刻只允许一个线程执行一个关键部分的代码. 条件变量是用来等待而不是用来上锁的,条用来自动阻塞一个线程,直到某特殊情况发生为止,通常条件变量和互斥锁同时使用. 线程的信号量与进程间通信中使用的信号量的概念是一样,它是一种特殊的变

iOS应用程序间共享数据(转)

我们知道iOS由于沙盒的存在,应用程序不能越过自己的区域去访问别的存储空间的内容,不过可能有许多场景我们需要在应用程序之间共享数据,比如多个应用共用用户名密码进行登录等.虽然我们不能直接通过文件系统来分享数据,不过还是有些方法可以实现,为了方便说明,这里同时创建了两个工程Example1和Example2,实现这两个app之间的信息共享,Example1负责写数据,Example2负责读数据,具体的demo代码可以到这里获取 UIPasteboard 剪贴板是应用程序之间传递数据的简单方式,建议

联系人提供程序

联系人提供程序是一个强大而又灵活的 Android 组件,用于管理设备上有关联系人数据的中央存储库. 联系人提供程序是您在设备的联系人应用中看到的数据源,您也可以在自己的应用中访问其数据,并可在设备与在线服务之间传送数据. 提供程序储存有多种数据源,由于它会试图为每个联系人管理尽可能多的数据,因此造成其组织结构非常复杂. 为此,该提供程序的 API 包含丰富的协定类和接口,为数据检索和修改提供便利. 本指南介绍下列内容: 提供程序基本结构 如何从提供程序检索数据 如何修改提供程序中的数据 如何编

手机卫士08_应用程序的flags_PopupWidnow悬浮窗体

1,应用管理的ui界面 条目界面的参考ui ①然后显示在ListView上即可(记得优化,程序大小的格式化等) ②获取ListView需要花费一定时间,所以放在子线程,再通过runOnUiThread()更新ui即可 ③创建一个FrameLayout,包含ListView,然后设置一个等待框,在获取的时候显示在页面上. 2,应用程序的flags (可以区分应用程序的安装位置,系统和用户安装的程序等) 2.1 ①在遍历每一个包信息的时候packInfo.application.flags(可能是多

黑马程序员_JavaSE学习总结第19天_IO流1

------- android培训.java培训.期待与您交流! ----------  19.01  集合的特点和数据结构总结 HashSet.HashMap.Hashtable判断元素唯一性的方式: 通过对象的hashCode和equals方法来完成元素唯一性 如果对象的hashCode值不同,那么不用判断equals方法,就直接存储到哈希表中. 如果对象的hashCode值相同,那么要再次判断对象的equals方法是否为true. 如果为true,视为相同元素,不存.如果为false,那么

黑马程序员-集合框架(Map和Collections)

--Java培训.Android培训.iOS培训..Net培训.期待与您交流!--- 一.概述 Map是一种存储键值对的存储容器,而且保证键的唯一性.提供一种以"键"标识"值"的数据存储方式.接口形式为:Map<K,V>,其中K是此映射所维护的键的类型,V是映射值的类型.其有两个常用子类,HashMap和TreeMap,另有HashTable与HashMap功能类似,是早期版本.三者特点与不同如下: HashMap:JDK1.2版本出现,底层使用哈希表数